Hi Hanif,

From a protocol perspective the client application should use 
$expand=InsuranceContracts to explicitly request the contracts of a policy. 

Always implicitly expanding the contracts even if the client didn't ask for 
them has the drawback of increasing the response size, which can be an issue in 
slow networks (mobile scenarios). One of the main benefits of OData is that the 
client has control over the amount of data it requests, down to the field level 
with $select.

Regarding the implementation details: I don't find the questions trivial, 
especially because I can't answer them :-)

Can one of the implementation experts please chime in?

Thanks!
--Ralf


-----Original Message-----
From: Rajabali, Hanif 
Sent: Wednesday, 12. February 2014 22:19
To: Handl, Ralf
Cc: Xu, Yao Feng; Klevenz, Stephan; [email protected]
Subject: RE: How to resolve 1 Entity type that has a property which is a list 
of a complex type (cadinality 0.. *)

Hi Ralf, thank you for your response....  here is my scenario:
I have an entity that represents an InsurancePolicy which has several 
single-valued complex type properties and a multi-valued   InsuranceContract 
type that could be 0..* under this policy.   The InsuranceContract I've made 
into an Entity type and it has its own complex properties.    The 
InsuranceContract object does not have any id per se that points back to the 
InsurancePolicy.     I'm having trouble defining the navigation property 
elements for the InsurancePolicy to InsuranceContract relationship and then 
mapping the whole InsurancePolicy object including the InsuranceContracts to a  
List<Map<String, Object>> for consumption by EntityProvider.writeFeed().   
Everything resolves fine for the InsurancePolicy except for the display of the 
InsuranceContract.     Do I have to use the $expand system option in order to 
display the navigational elements or can it just be done by some default 
switch?   What do I need to add in readEntitySet() in order to resolve my 
navigation properties and have them included as part of the Odataresponse?    

Sorry for the triviality of the question... 
Thank you for your help!
Hanif

-----Original Message-----
From: Handl, Ralf 
Sent: Wednesday, February 12, 2014 4:17 AM
To: Rajabali, Hanif
Cc: Xu, Yao Feng; Klevenz, Stephan; [email protected]
Subject: RE: How to resolve 1 Entity type that has a property which is a list 
of a complex type (cadinality 0.. *)

Hi Hanif,

This will be possible with OData 4.0, in OData 2.0 complex properties are 
single-valued. 

A typical work-around with OData 2.0 is to use a separate entity type and a 
navigation property with cardinality * instead of the list-valued complex 
property. In many use cases the items in the list actually can be uniquely 
identified, and are in fact stored in a separate table. So this "work-around" 
actually is making the underlying data model visible again.

What is your use case?

Regards!
--Ralf

-----Original Message-----
From: Rajabali, Hanif [mailto:[email protected]] 
Sent: Tuesday, 11. February 2014 17:39
To: Klevenz, Stephan
Cc: Xu, Yao Feng; [email protected]
Subject: How to resolve 1 Entity type that has a property which is a list of a 
complex type (cadinality 0.. *)

Hi Stephan and the great Olingo community!   I have a situation where I'm 
trying to model an oData service from a webservice that returns back a lot of 
data in the form of nested complex types (a very complex xsd) .    I basically 
have 1 entity type that represents the main webservice response object.    And 
that entity type has several complex/simple type properties that I've mapped to 
match.    When ready to write the odata response, I can map them to a 
List<Map<String,Object>> as per what odata expects by using reflection etc 
etc..... the problem I'm having is if I have a List of complex type as part of 
my entity type.    Is there a way for me to create a complex property and 
define it as a list or collection that has cardinality 0..*?   I don't have any 
navigation properties as I only have the 1 entity.   So once I get it correctly 
defined, my metadata should show that particular field/property as a collection 
am I correct?     
Any help with some code examples/snippets would be greatly appreciated!

Thank you!
Hanif


On 16.01.14 22:44, "Rajabali, Hanif" <[email protected]> wrote:

>Hello Sven and the olingo community!   Needed your help again please :)
> As it stands, we are using the olingo library to generate odata
>services.   We are sort of using the odata services as a proxy to invoke
>other services so its not really being used to perform CRUD operation on
>a backend database per se, but more so to simply relay the request(s) to
>underlying service(s).    For example, we have an Account.svc which
>simply gets accounts from another disparate rpc service.   We have
>Product.svc which gets products from another webservice.     I realize
>this is not really what odata is meant to be used for but using odata to
>communicate with a ui layer (sap ui5) is a strict requirement for us.
>So now, since we have multiple services, we have not defined a
>singleprocessor as in the car/manufacturer example.   Instead, we have
>defined separate processors which extend from OdataSingleProcessor i.e)
>AccountProcessor, ProductProcessor and have defined a delegator (also
>extends OdataSingleprocessor) which through reflection, and our own
>defined annotations, determines,  which processor to use.    We have also
>defined our own annotations to represent, simple/complex types which get
>mapped at runtime through the edmprovider instead of hard coding entity
>field simpl/complex types as shown in the sample app. (Unless there is
>something out of the box we can use??)
>
>We now need to implement FunctionImport.   The car/manufacturer example
>defines it in the edmprovider but doesn't provide a concrete
>implementation for us to use as an example.   We would like to create
>such functionimports to be able to in turn call services that don't
>really tie into an EntityType.   We also don't use JPA... can you
>illustrate how we might perform something like:
>http://myhost/MyService.svc/MyFunctionImport(parameter1....parameterN)?
>
>Thank you so much!
>Hanif
>
>-----Original Message-----
>From: Kobler-Morris, Sven [mailto:[email protected]]
>Sent: Thursday, December 19, 2013 5:00 AM
>To: [email protected]
>Subject: FW: How to implement a filter or query using Olingo API
>
>Hello Hanif,
>
>using  the filter is the better option, because that is what the $filter
>system query parameter  is made for (similar to the "where " clause
>in SQL statements). A ODATA client can request only entities which
>pass the filter expression.
>
>To avoid a manual parsing of the $filter parameter the odata library
>does the parsing and creates a filter tree which can be obtained from the
>UriInfo object  supplied as input parameter "uriInfo" on the "readEntity"
>method. The filter tree can be used directly or with help of the Visitor
>pattern. 
>
>Generally  you can use the filter tree to create a query string which is
>understood by your data layer and pass this query string to the data
>layer (potentially insecure) or you can filter a entity set manually in
>your layer.
>
>I recommend to implement the interface "ExpressionVisitor" to either
>create the query string for the data layer or to the manual filtering.
>
>An potential solution for manual filtering would be to implement
>and ExpressionVisitor  and use this visitor on each entity set/data
>record 
>you want to filter.
>
>E.g.
>...
>public class AccountFilter implements ExpressionVisitor
>...
>use the methods:
>visitMember -> to read and validate the propertyName
>                                (from your sample only accountName is
>allowed)
>               and return the column name
>visitLiteral -> to read the accountName value (e.g. "Account1")
>               and return it
>visitBinary -> if the parameter is "eq"  return
>               whether property accountName on  the current
>               entityset/datarecord is equal to the literal or not
>...
>As sample a rough flow would be:
>- read the entityset ( all records)
>- get the filter tree from uriInfo
>- for each record
>-     if ( filtertree->accept(yourAccountFilter) != true) {
>       delete record from entityset    
>      }
>- next record
>- serialize the remaining records
>
>The call sequence for $filter=AccountName eq 'Account1') would be
>1. visitMember
>2. visitLiteral 
>3. visitBinary (left operant is "AccountName" right opterand is
>"Account1")
>
>Consider also how your service should behave in case of more complex
>filters
>Like:
>$filter='Account1' eq  AccountName
>$filter='Account1' eq  AccountName or AccountName eq 'Acount2'
>
>However this is not the fastest solution. It is always faster to
>transform the 
>filtertree into a query which can be used directly in your datalayer, but
>always
>consider security checks before using this to avoid script injection
>etc...
>
>regards,
>Sven
>
>----
>
>On 17.12.13 22:55, "Hanif Rajabali" <[email protected]> wrote:
>
>>Hello all, sorry if this is too rudimentary of a question but I have
>>setup an oData service with the help of the great tutorials posted on the
>>olingo site.    The tutorials cover the Resource path but I'd like to now
>>perform a system or custom query.   Below I've included my basic
>>$metadata document which has 2 simple entities: Account/Producer
>>(EntitySets: Accounts/Producers).    As it stands I can perform an
>>operation like /Accounts(1) which is taken care of in my implementation
>>of readEntity() in my ODataSingleProcesser shown below.    Now I'd like
>>to get say an account by 'AccountName'.   So would it be system $filter
>>like: /Accounts?$filter=AccountName eq 'Account1'  or would it be a
>>custom query like: /Accounts?AccountName='Account1'
>>
>> 
>>
>>And, where would I implement it?   Within readEntity?  If so, could you
>>give me some guidance on the implementation?    I saw the sample of the
>>visitor pattern to transform an odata query into a jdbc query but my
>>odata service is connecting to another disparate service:
>>this.accountService so I just need to basically parse the query and then
>>perform the corresponding service call based on the query name/value
>>pair.    Should I leverage what was shown in the visitor example?  If so,
>>how does that 'plugin' to my OdataSingleProcessor implementation?
>>
>> 
>>
>>public class WPODataSingleProcessor extends ODataSingleProcessor {
>>
>>.....
>>
>>public ODataResponse readEntity(GetEntityUriInfo uriInfo, String
>>contentType) throws ODataException {
>>
>>                              logger.info("custom query options: " +
>>uriInfo.getCustomQueryOptions());
>>
>>                              if (uriInfo.getNavigationSegments().size()
>>== 0) {
>>
>>                                             EdmEntitySet entitySet =
>>uriInfo.getStartEntitySet();
>>
>>                                             WPEntitySet startEntitySet =
>>WPEntitySet.fromString(entitySet.getName());
>>
>>                 
>>
>>                                             int id;
>>
>>                                             switch(startEntitySet) {
>>
>>                                             case ACCOUNTS:
>>
>>                                                            id =
>>getKeyValue(uriInfo.getKeyPredicates().get(0));
>>
>>                                                            Map<String,
>>Object> account = this.accountService.getAccount(id);
>>
>> 
>>
>>                                                            if (account
>>!= null) {
>>
>>                 
>> URI serviceRoot = getContext().getPathInfo().getServiceRoot();
>>
>>                 
>> ODataEntityProviderPropertiesBuilder propertiesBuilder =
>>EntityProviderWriteProperties.serviceRoot(serviceRoot);
>>
>> 
>>
>>                 
>> return EntityProvider.writeEntry(contentType, entitySet, account,
>>propertiesBuilder.build());
>>
>>                                                            }
>>
>>                 
>>
>>                                             case PRODUCERS:
>>
>>                                                            id =
>>getKeyValue(uriInfo.getKeyPredicates().get(0));
>>
>>                                                            Map<String,
>>Object> producer = this.producerService.getProducer(id);
>>
>> 
>>
>>                                                            if (producer
>>!= null) {
>>
>>                 
>> URI serviceRoot = getContext().getPathInfo().getServiceRoot();
>>
>>                 
>> ODataEntityProviderPropertiesBuilder propertiesBuilder =
>>EntityProviderWriteProperties.serviceRoot(serviceRoot);
>>
>> 
>>
>>                 
>> return EntityProvider.writeEntry(contentType, entitySet, producer,
>>propertiesBuilder.build());
>>
>>                                                            }
>>                 
>>
>>                                             }
>>
>> 
>>
>>                                             throw new
>>ODataNotFoundException(ODataNotFoundException.ENTITY);
>>
>> 
>>
>>                              }
>>
>> 
>>
>>                              throw new ODataNotImplementedException();
>>
>>               }
>>
>> 
>>
>>...
>>
>> 
>>
>>}
>>
>> 
>>
>> 
>>
>>-------------------
>>
>>My $metadata:
>>
>>-------------------
>>
>><edmx:Edmx xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx";
>>Version="1.0">
>>
>><edmx:DataServices
>>xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";
>>m:DataServiceVersion="1.0">
>>
>><Schema xmlns="http://schemas.microsoft.com/ado/2008/09/edm";
>>Namespace="com.sap.workplace.uiservice.odata">
>>
>><EntityType Name="Account">
>>
>><Key>
>>
>><PropertyRef Name="Id"/>
>>
>></Key>
>>
>><Property Name="Id" Type="Edm.Int32" Nullable="false"/>
>>
>><Property Name="AccountId" Type="Edm.String" Nullable="false"/>
>>
>><Property Name="AccountType" Type="Edm.String" Nullable="false"/>
>>
>><Property Name="AccountName" Type="Edm.String" Nullable="false"/>
>>
>><Property Name="AccountNumber" Type="Edm.String" Nullable="false"/>
>>
>><Property Name="Address"
>>Type="com.sap.workplace.uiservice.odata.Address"/>
>>
>></EntityType>
>>
>><EntityType Name="Producer">
>>
>><Key>
>>
>><PropertyRef Name="Id"/>
>>
>></Key>
>>
>><Property Name="Id" Type="Edm.Int32" Nullable="false"/>
>>
>><Property Name="ProducerName" Type="Edm.String" Nullable="false"/>
>>
>><Property Name="ProducerId" Type="Edm.String" Nullable="false"/>
>>
>><Property Name="FirstName" Type="Edm.String" Nullable="false"
>>MaxLength="100"/>
>>
>><Property Name="LastName" Type="Edm.String" Nullable="false"
>>MaxLength="100"/>
>>
>><Property Name="Address"
>>Type="com.sap.workplace.uiservice.odata.Address"/>
>>
>></EntityType>
>>
>><ComplexType Name="Address">
>>
>><Property Name="Address1" Type="Edm.String" Nullable="true"/>
>>
>><Property Name="Address2" Type="Edm.String" Nullable="true"/>
>>
>><Property Name="City" Type="Edm.String" Nullable="true"/>
>>
>><Property Name="State" Type="Edm.String" Nullable="true"/>
>>
>><Property Name="Country" Type="Edm.String" Nullable="true"/>
>>
>><Property Name="Zip" Type="Edm.String" Nullable="true"/>
>>
>></ComplexType>
>>
>><EntityContainer Name="SAPWorkplaceEntityContainer"
>>m:IsDefaultEntityContainer="true">
>>
>><EntitySet Name="Accounts"
>>EntityType="com.sap.workplace.uiservice.odata.Account"/>
>>
>><EntitySet Name="Producers"
>>EntityType="com.sap.workplace.uiservice.odata.Producer"/>
>>
>></EntityContainer>
>>
>></Schema>
>>
>></edmx:DataServices>
>>
>></edmx:Edmx>
>>
>> 
>>
>>
>>
>

Reply via email to