Accessing OData Property - odata

I am quite new to oData webservices. I would like to get and populate the following output on mobile platform. I could able populate the following url data on mobile platform http://services.odata.org/V4/Northwind/Northwind.svc/Customers . However, once I started on doing another exercise. I am stuck with the following odata output. How could I access to properties, such as Name or Description?
PUT /OData/OData.svc/Products(1) HTTP/1.1 Host: services.odata.org DataServiceVersion:
1.0 MaxDataServiceVersion: 2.0 accept: application/atom+xml
content-type: application/atom+xml Content-Length: 1181
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Entry xml:base="http://services.odata.org/OData/OData.svc/"
xmlns:d=" http://schemas.microsoft.com/ado/2007/08/dataservices"
xmlns:m=" http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
xmlns="http://www.w3.org/2005/Atom">
<id>http://services.odata.org/OData/OData.svc/Products(1)</id>
<title type="text"></title>
<updated>2010-02-28T10:23:02Z</updated>
<author>
<name />
</author>
<Link rel="edit" title="Product" href="Products(1)" />
<category term="DataServiceProviderDemo.Product"
scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<content type="application/xml">
<m:properties>
<d:ID m:type="Edm.Int32">1</d:ID>
<d:Name>Milk</d:Name>
<d:Description>Low fat milk</d:Description>
<d:ReleaseDate m:type="Edm.DateTime">1995-10-21T00:00:00</d:ReleaseDate>
<d:DiscontinuedDate m:type="Edm.DateTime" m:null="true" />
<d:Rating m:type="Edm.Int32">4</d:Rating>
<d:Price m:type="Edm.Decimal">4.5</d:Price>
</m:properties>
</content>
</Entry>

There are several ways to access specific properties, as there are two kinds of properties on a entity: a non-navigation property and a navigation property.
A non-navigation property is either a primitive type property, a collection of primitive type property, a complex type property, a complex type property, or a stream property. When you query the entity set or a specific entity, the values of the non-navigation properties are by default inline of the entity payload:
e.g. ID, Name, Description, etc. are inline when you query:
GET http://services.odata.org/v4/odata/odata.svc/Products
If you want to choose the properties you need, you can use the $select query option. E.g.
GET http://services.odata.org/v4/odata/odata.svc/Products?$select=ID,Name
By appending such query option, you will find only the properties you need inline of the payload.
If you want to only access the property value, you should append the property name as a segment to the request URL to a single entity. E.g.
GET http://services.odata.org/v4/odata/odata.svc/Products(1)/ID
There is another kind of property: the navigation properties. They are either an entity type property or a collection of entity type property. Navigation properties describes the relationship between the different entities in the service. An example is the Categories navigation property on the Product entity.
Navigation properties are by default not shown inline of the entity payload. In order to include them inline, the $expand query option needs to be used:
GET http://services.odata.org/v4/odata/odata.svc/Products?$expand=Categories
If you want to only access the navigation property, the request URL is similar as it is for non-navigation properties:
GET http://services.odata.org/v4/odata/odata.svc/Products(1)/Categories
To learn more about how to issue different OData requests for different scenarios and what the URL conventions is, the following materials are helpful:
The tutorials on OData.org: http://www.odata.org/getting-started/basic-tutorial/ (basic), http://www.odata.org/getting-started/advanced-tutorial/ (advanced).
The URL convention spec of OData V4: http://docs.oasis-open.org/odata/odata/v4.0/os/part2-url-conventions/odata-v4.0-os-part2-url-conventions.html
The protocol spec of OData V4: http://docs.oasis-open.org/odata/odata/v4.0/os/part1-protocol/odata-v4.0-os-part1-protocol.html

Related

SAPUI5 - how to set value to input parameter in binding dynamically

In my XSOData service I have an entity based on calculation view with input parameters. I can to set these parameters as constants in my XML view, i.e.
<List items="{dicts>/AncParams(p_dict_name='GROUPS',p_rec_id=2)/Results}" >
<StandardListItem
title="{dicts>NAME}"
/>
</List>
and it will work fine.
But how I can set parameters p_dict_name and p_rec_id dynamically? I tried to use expression bindings to get values for parameters from another model (something like this: <List items="{= ${dicts>/AncParams(p_dict_name='GROUPS',p_rec_id=${DictUIProps>/parentId})/Results} }" >) but with no luck. As I understand, expression bindings won't work. Is there any other way?
As far as I'm aware you can't do the aggregation binding dynamically through XML. At least not in the versions I have used and I have to admit I haven't re-checked in a while. The string never gets interpreted for inner bindings before it's applied to the model.
The way I do this is through the controller:
<List id="myList" />
and in your controller (onBeforeRendering or onPatternMatched or wherever your model and view are known to the controller):
this.getView().byId('myList').bindItems({
model: 'dicts',
path: `{/AncParams(p_dict_name='${p_dict_name}',p_rec_id=${p_rec_id})/Results}`,
template: new sap.m.StandardListItem({
title: '{dicts>NAME}'
})
});
you can use the getModel('dicts').createKey function to generate the path name which is a little cleaner I suppose.
This is the way to apply dynamic filters as well, In case you ever build those.

Breeze doesn't post navigation properties

I inherited an OData service that exposes - among other things - a type called Evaluation. This type contains a lot of primitive type properties (int, bool mostly) and two navigation properties/links to other entities.
Breeze is configured to use the v3/'original' odata adapter:
breeze.config.initializeAdapterInstance('dataService', 'odata', true);
If I create a new entity
var manager = new breeze.EntityManager('odataEndPointHere');
manager.fetchMetadata().then(() => {
var newEvaluation = manager.createEntity('Evaluation', {Name:'Foo'});
});
then this newEvaluation will reference all primitive fields and the navigation properties (called Validation - a TPH type - and Replacements - a ~normal~ 1:1 entity relation). If I expand() that relation, I can query for existing Evaluations and will see the expected Validation value.
Grabbing an existing Validation instance and assigning it seems to work as well:
manager.fetchEntityByKey('Validation', existingIdHere).then(validation => {
newEvaluation.Validation = validation; // works, while assigning a non-entity throws
});
But if I call manager.saveChanges(); the server reports that there's no (mandatory) Validation link. Looking at the POST to the $batch endpoint I see that breeze really only posts a subset of the Evaluation type, only posts the primitive fields and none of the navigation properties. This happens for both existing (fetched and updated) and new (createEntity) objects.
Now, I understand that I've yet to create a small test case - given that this is a service that I cannot directly control I'm still trying to figure out how I'm going to provide a reduced recipe for reproduction.
That said:
breeze can query all my entities, just fine. Expanding the navigation properties works flawlessly
breeze completely ignores the very same properties during saveChanges() for me
(unrelated?) breeze offers no way for me to set the FK ID only (http://breeze.github.io/doc-js/navigation-properties.html, "Setting the Foreign Key directly") although it does list the navigation properties in manager.metadataStore.getEntityType("Evaluation").navigationProperties
Edit:
The $metadata result contain this for the entities in question:
<EntityType>
<!-- snip the rest --->
<NavigationProperty Name="Evaluations" Relationship="MyNamespace.Entities.FK_Evaluation_Validation" ToRole="Evaluation" FromRole="Validation" />
</EntityType>
and later:
<AssociationSet Name="FK_Evaluation_Validation" Association="MyNamespace.Entities.FK_Evaluation_Validation">
<End Role="Validation" EntitySet="Validations" />
<End Role="Evaluation" EntitySet="Evaluations" />
</AssociationSet>

Why does JSF generate names in addition to IDs?

The generation / use of IDs is fairly clear, for reassociating submitted components to the view tree.
But why does JSF generate names as well? Does it use them internally?
It's required by HTML specification and used by Servlet API. Webbrowsers use input field names as HTTP request parameter names. They do not use input field IDs for that as it would otherwise be impossible to send multiple values per name (select multiple, checkbox groups, etc).
I.e.
<h:inputText id="foo">
generates
<input type="text" id="formId:foo" name="formId:foo" />
which gets in client side prepared (by webbrowser's internal code) in HTTP request as
element.getAttribute("name") + "=" + element.getAttribute("value")
and gets in server side extracted (by UIComponent#decode()) from the HTTP request as
String foo = request.getParameter(component.getClientId());
See also:
Difference between id and name attributes in HTML
How to transfer data from JSP to servlet when submitting HTML form
ServletRequest.getParameterMap() returns Map<String, String[]> and ServletRequest.getParameter() returns String?

URL parameter as property binding

Is it possible to use a URL parameter as a property binding in UI5?
My problem is that I want to have different OData collections placed in the same UI5 aggregation. For example let's say I've "/Car("Mustang")/parts" and "/Car("Whatever")/parts". Both of them can be placed in the same view.
The application's URL contains the keyword like http://something/#/carMustang. This URL is coming from a routing pattern like "car{carHandle}".
How am I supposed to do stuff like this:
<List items="{/Car({carHandle})/parts}">
<StandardListItem title={someProperty}>
</StandardListItem>
</List>
So what would be the best practice to do this? I would like to avoid nasty fiddles in the controller.
In your view:
<List id="parts" items="{parts}">
<StandardListItem title="{someProperty}"/>
</List>
In your controller code which reacts on matched routes:
var carHandle = event.getParameter("carHandle");
this.byId("parts").bindObject("/Car/" + carHandle);

How do I break the tyranny of the clientID?

My least favorite part of coding JSF 2.0 forms has to do with the handing of the id attributes of the various input elements. I am forever having trouble coding the clientID of the target component from within the backing bean, particularly since PrimeFaces tabView now includes the id of the p:tab element as part of the clientID. I waste tons of time coding, testing, then re-coding those clientIDs.
It is reminiscent of older-style assembly language programming where you have to generate tons of label names for your branches and loops. I've done of enough of that for a lifetime.
One approach I am trying is to use only auto-generated id attributes. For example one line of my form might look like this.
<h:outputLabel value="Full Name:" />
<p:inputText value="#{editUser.user.fullName}"
binding="#{editUser.compFullName}"/>
<p:message for="#{editUser.compFullName.clientId}" />
Note that I do not have an explicit id attribute. Then in the backing bean:
String clientID = getCompFullName().getClientId();
msg = new FacesMessage(FacesMessage.SEVERITY_INFO,
"Summary Message For Full Name", "Detail Message Full Name");
FacesContext.getCurrentInstance().addMessage(clientID, msg);
This always works, even if the component has a complex clientID, such as when PrimeFaces inserts the p:tab id into the clientID. (Which it does starting v 3). Rearranging the form never breaks anything.
It is, however, laborious, since I have to create UIComponent properties, getters and setters, and bind them in the form with binding attributes. Can anyone suggest a better way of doing this?
since I have to create UIComponent properties, getters and setters, and bind them in the form with binding attributes. Can anyone suggest a better way of doing this?
It's not required to bind the component to some backing bean if you don't use it in there at all. Just bind it to the view instead:
<p:inputText value="#{editUser.user.fullName}"
binding="#{compFullName}"/>
<p:message for="#{compFullName.clientId}" />
To make the code more self-documenting, I suggest to put a HashMap in the request scope by faces-config.xml:
<managed-bean>
<description>Holder of all component bindings.</description>
<managed-bean-name>components</managed-bean-name>
<managed-bean-class>java.util.HashMap</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
with
<p:inputText value="#{editUser.user.fullName}"
binding="#{components.fullName}"/>
<p:message for="#{components.fullName.clientId}" />
Adding messages is supposed to be done by a Converter or a Validator which is trowing it as a ConverterException or ValidatorException respectively. It will automatically end up in the right message holder. Or if it are informal messages, just add it on the client ID of the UIComponent which is already available as method argument.
See also:
JSF component binding without bean property

Resources