How to filter by OData nested dynamic property? - odata

I have an open type entity that is accessed by foo.net/items.
The entity is defined as:
<EntityType Name="myEntity" OpenType="true">
<Key>
<PropertyRef Name="name" />
</Key>
<Property Name="name" Type="string" />
</EntityType>
An entity instance may look something like this:
{
"name": "foo",
"location": {
"country": "USA"
}
}
How can I reference the country property in my filter odata option? Is this the correct approach?
foo.net/items?$filter=location/country ne null and location/country eq 'USA'.
I believe the above is correct because it is a valid way to reference a property as per the ABNF in OData V4.

Yes, you can reference nested property by parentProperty/childProperty.
In your case is not necessary to check if nested property in not null, so you can simplify the query like this:
foo.net/items?$filter=location/country eq 'USA'

Related

Display a 'one to many' association with SAP Fiori annotations in CAP

I try do do a DB project with SAP cap. I want to display all entities associated with the Parent entity. If the Association is one to one it works fine. But if it is one to many it doesn't display anything.
--I have following Schema definition:
entity Company{
key ID : Integer #title: 'Company ID';
cName : String #title: 'Company name';
pers: Association to many Person on pers.comp = $self; //association to one works
}
entity Person{
key ID : Integer #title: 'ID';
pName: String #titel: 'Name';
comp: Association to Company;
}
--And following fiori Annotations:
annotate Admin.Company with #(
UI.LineItem:[
{$Type: 'UI.DataField', Value: cName},
],
UI.HeaderInfo:{
TypeName: 'Company',
TypeNamePlural: 'Companys'
},
);
//Details view:
annotate Admin.Company with #(
UI: {
HeaderInfo: {
Description: {Value: ID}
},
HeaderFacets: [
{$Type: 'UI.ReferenceFacet', Target: '#UI.FieldGroup#Comp'},
],
Facets: [
{$Type: 'UI.ReferenceFacet', Target: '#UI.FieldGroup#Pers'}
],
FieldGroup#Comp: {
Data: [
{Value: cName},
]
},
FieldGroup#Pers: {
Data: [
{Value: pers.pName},
]
},
});
The Admin Service is just a projection on the given entities.
Does anyone know what I have to change to get pers.Name displayed in a list or something like that?
As already mentioned if I change in Schema definition 'association to many' into 'association to one' it works. But I want it to have more than one entity associated.
If you are using the Fiori Elements List Report Object Page template I think you can only use a 1:1 association. This is the intended design of the floorplan (List → Detail). How should Fiori Elements know which of the "many" person items should be bound to the one detail view.
However, what you can and probably want to do is binding the detail view to the selected company item and create a field group. There you can display a table which refers to a different entity. So, you keep your schema.cds as it currently is but change your annotation.cds:
annotate Admin.Company with #(
UI: {
// columns of the list view
LineItem:[
{$Type: 'UI.DataField', Value: cName},
],
// title (singular/plural) of the list view and description of the detail view
HeaderInfo:{
TypeName: 'Company',
TypeNamePlural: 'Companies',
Description: {Value: ID}
},
// facet for the person table
HeaderFacets: [
{$Type: 'UI.ReferenceFacet', Target: 'Person/#UI.LineItem'}
]
);
annotate Admin.Person with #(
// person table (only displayed in detail view) with columns
UI.LineItem: [
{$Type: 'UI.DataField', Value: 'comp/cName'},
{$Type: 'UI.DataField', Value: 'pName'}
]);
It might be that the code above doesn't work right away because I didn't test it. But I created a working example with the Northwind OData V2 Service using the customer entity for the list view and the order entity in a table in the detail view. You can recreate the example by running the Fiori List Report Object Page wizard with the OData service URL https://services.odata.org/Northwind/Northwind.svc/ and the main entity Customer. When the generation of the project is finished you can replace the content of the annotation.xml with the following:
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
<edmx:Reference Uri="https://sap.github.io/odata-vocabularies/vocabularies/Common.xml">
<edmx:Include Namespace="com.sap.vocabularies.Common.v1" Alias="Common" />
</edmx:Reference>
<edmx:Reference Uri="https://sap.github.io/odata-vocabularies/vocabularies/UI.xml">
<edmx:Include Namespace="com.sap.vocabularies.UI.v1" Alias="UI" />
</edmx:Reference>
<edmx:Reference Uri="https://sap.github.io/odata-vocabularies/vocabularies/Communication.xml">
<edmx:Include Namespace="com.sap.vocabularies.Communication.v1" Alias="Communication" />
</edmx:Reference>
<edmx:Reference Uri="/Northwind/Northwind.svc/$metadata">
<edmx:Include Namespace="NorthwindModel" />
<edmx:Include Namespace="ODataWebV3.Northwind.Model" />
</edmx:Reference>
<edmx:DataServices>
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="local">
<Annotations Target="NorthwindModel.Customer">
<Annotation Term="UI.LineItem">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="CompanyName" />
</Record>
</Collection>
</Annotation>
<Annotation Term="UI.Facets">
<Collection>
<Record Type="UI.ReferenceFacet">
<PropertyValue Property="Target" AnnotationPath="Orders/#UI.LineItem" />
</Record>
</Collection>
</Annotation>
</Annotations>
<Annotations Target="NorthwindModel.Order">
<Annotation Term="UI.LineItem">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="OrderID" />
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="Customer/CompanyName" />
</Record>
</Collection>
</Annotation>
</Annotations>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
I hope this solves your problem. If you have any questions feel free to ask.

How to build an edit form for a list of strings in Grails?

I have a Grails domain class with a list of strings in it, and I want to edit these strings. For the sake of simplicity let's assume that the list is fixed size. Here's what I have:
MyEntity.groovy:
class MyEntity {
String name
List variables = ['one', 'two', 'three']
static hasMany = [
variables: String,
]
}
_fields/myEntity/variables/_widget.gsp:
<g:textField name="variables[0]" value="${value[0]}" />
<g:textField name="variables[1]" value="${value[1]}" />
<g:textField name="variables[2]" value="${value[2]}" />
This renders text fields for each element in the list that are prefilled with the correct values. However, when I edit the values and sumbit the form my edits get discarded. What am I missing?
Ok, I found it myself. The input fields all need to have the name of the domain property, without any index:
<g:textField id="variables[0]" name="variables" value="${value[0]}" />
<g:textField id="variables[1]" name="variables" value="${value[1]}" />
<g:textField id="variables[2]" name="variables" value="${value[2]}" />

Can't we link a grails form to a bean

As in Struts n JSF, we link a form to a bean(eg. backing bean in JSF).
But in grails, we are using params to set values of the bean. Is there any other way to automatically map a form to the bean?
Grails has the possibility to auto bind values from the params map to a given domain instance / command object. This can be achieved by defining the correct beans as a parameter for your controller methods. Take this example:
Controller:
class AuthorController {
def save(Author author) {
// matching param values are bound to the author instance
assert params.name == "myName"
assert author.name == "myName"
}
}
gsp with form:
<g:form controller="author" action="save">
<g:field name="name" value="myName" />
<g:submitButton name="save" value="Save" />
</g:form>
Sometimes is better to use the Command Objects provided by Grails, the domain class can be wrapped only matching the name of the form fields with the attributes names of the class.
But Command Objects can provide an intermediate layer of validation and abstraction to generate the model bean.
http://grails.org/doc/2.3.0/guide/single.html#commandObjects

How to get all the values from a Groovy Map in a select of a GSP page

Let's say we have a map like:
def mostBeautifulCities =
[
cadiz : "Cádiz",
KeyForCity2 : "some value for city2"
]
How could we list all values? (I did not find a easy way looking at the Groovy JDK documentation).
I want to show all values in a select control:
<g:select id="city" name="city"
from="${ mostBeautifulCities.(...) }"
noSelection="${['':'Select a ugly city...']}" />
<g:select from="${mostBeautifulCities.entrySet()}" name="city" optionKey="key" optionValue="value" ></g:select>

LINQ to SQL Table Dependency

If I have two tables... Category and Pet.
Is there a way in LINQ to SQL to make the result of the joined query map to a another strongly typed class (such as: PetWithCategoryName) so that I can strongly pass it to a MVC View?
I currently have Category and Pet classes... should I make another one?
Maybe I missing something here. Can any of you enlighten me?
from p in petTable
join c in categoryTable on p.CategoryId equals c.Id
where (c.Id == categoryId.Value)
select new
{
p.Id,
p.Name,
p.Description,
p.Price,
CategoryName = c.Name
}
<?xml version="1.0" encoding="utf-8" ?>
<Database Name="PetShop" xmlns="http://schemas.microsoft.com/linqtosql/mapping/2007">
<Table Name="Category" Member="PetShop.Models.Category">
<Type Name="PetShop.Models.Category">
<Column Name="Id" Member="Id" IsDbGenerated="true" IsPrimaryKey="true" />
<Column Name="Name" Member="Name" />
<Column Name="Description" Member="Description" />
</Type>
</Table>
<Table Name="Pet" Member="PetShop.Models.Pet">
<Type Name="PetShop.Models.Pet">
<Column Name="Id" Member="Id" IsDbGenerated="true" IsPrimaryKey="true" />
<Column Name="Name" Member="Name" />
<Column Name="Description" Member="Description" />
<Column Name="ImageUrl" Member="ImageUrl" />
<Column Name="Price" Member="Price" />
<Column Name="CategoryId" Member="CategoryId" />
<Association Name="FK_Pet_Category" Member="Category" ThisKey="CategoryId" OtherKey="Id" IsForeignKey="true" />
</Type>
</Table>
</Database>
How would I go about using LoadWith? I'm not finding much help online. Any good resources?
I found this online: http://blogs.msdn.com/wriju/archive/2007/10/04/linq-to-sql-change-in-datacontext-from-beta-1-to-beta-2.aspx
You would do something like:
var loadOption = new DataLoadOptions();
loadOption.LoadWith<Pets>(p => p.Category);
db.LoadOptions = loadOption;
var pets = from p in PetStoreContext.Pets
select p;
And then your pets query will already include category, so no trip to the database happens when you try to access category.
If you use the LoadWith LoadOption then your Pet query will do an eager load on categories, so that you will be able to do
MyPet.Category.Name without incurring an extra query, so you'll have the data joined and strongly typed without the risk of running multiple queries for Categories as you loop or bind on the Pet collection.
Or you can use stored procedures in Linq To SQL,the result is strongly typed.

Resources