4

I try to follow below document of olingo to create a odata service.

AnnotationProcessor

But I fail to create a entity with property whose type is a List of ComplexType. Anyone has an example of it. Or is it just not supported ?

Shiva
  • 6,677
  • 4
  • 36
  • 61
goodier
  • 395
  • 6
  • 18

2 Answers2

7

Maybe Utsav's answer was correct at that point of time, but Odata v4 does support an entity with property whose type is a "List of ComplexType".
Prove: In this sample entityType Person has property AddressInfo and its type is a collection of ComplexType:

<ComplexType Name="Location" OpenType="true">
  <Property Name="Address" Type="Edm.String" Nullable="false"/>
  <Property Name="City" Type="Microsoft.OData.SampleService.Models.TripPin.City" Nullable="false"/>
</ComplexType>
...
<EntityType Name="Person" OpenType="true">
  <Property Name="AddressInfo" Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Location)"/>
...
</EntityType>

Regarding Olingo implementation, in your CSDL provider you have to properly define your complex type entity, and then define the property, that you want to be a collection of this complex type. Then you have to correctly process the result.

1. Defining the metadata in CSDL provider

In your provider's getSchemas() method you have to declare your complex types:

    List <CsdlComplexType> complexTypes = new ArrayList<>();
    //...initialization of complexTypes list...
    schema.setComplexTypes(complexTypes);

In getEntityType() method you have to create your property as a collection of complex type objects:

    //...initialization of entityType...
    List<CsdlProperty> properties = new ArrayList<>();
    FullQualifiedName type;
    //...initialization of the type as a complex type...
    properties.add(new  CsdlProperty().setName("propertyName").setType(type).setCollection(true));
    entityType.setProperties(properties);
    //...

2. Processing the result

In your processor's implementation you have to correctly build your entity: for example, in readEntityCollection() method of EntityCollectionProcessor implementation you should have something similar to this:

    EntityCollection entities = new EntityCollection();
    List<Entity> eList = entities.getEntities();
    Entity e = new Entity();
    List<Map> data;
    //...initialization of complex type's data...
    List<ComplexValue> properties = new ArrayList<>();
    for (Object complexObject : data) {
        ComplexValue complexValue = new ComplexValue();
        for (Map.Entry<String, Object> entry : complexObject.entrySet()) {
                complexValue.getValue().add(new Property(null, entry.getKey(), ValueType.PRIMITIVE, entry.getValue()));
            }
        properties.add(complexValue);
    }
    e.addProperty(new Property(null, "propertyName", ValueType.COLLECTION_COMPLEX, properties););
    eList.add(e);

//...serialize and set the result to response
Taras Kohut
  • 2,505
  • 3
  • 18
  • 42
  • This answer is of great help to me as I'm working on an odata service. But after following practice I'm still blocked by one issue, that while trying to access entity sets, I got the error: Cannot find type with name: namespace.complexTypeName. what's interesting is that in metadata, the relationship between EntityType and it's property with ComplexType is correct, but when I try to get entitysets, I got the error. The answer is long ago, do you still have memory of the details? – Blangero Feb 26 '20 at 07:46
  • @Blangero it's impossible to answer you without a minimum reproducible code sample. See this project as an example: https://github.com/Hevelian/hevelian-olastic or ask a new question here – Taras Kohut Feb 26 '20 at 12:12
2

I came across for a similar requirement in my project yesterday. That is when I noticed your question which was unanswered. I have implemented an approach which works for me. I am describing it below. Hopefully, it will be of some help.

In nutshell: How I understand it as is that we cannot use ComplexType for having entity as a list. We need to use navigation property.

Problem Statement : I have to read an entity - EntityA. EntityA is related to EntityB. Relation is ONE-TO-MANY i.e. EntityA contains a list of EntityB. A typical JSON representation would be as follows:

EntityA:{
"id":"entityA_1",
"entityBList":[
     {//EntityB Element
        "id" : "entityB_1",
        "description":"value1"
     },
     {//EntityB Element
        "id" : "entityB_2",
        "description":"value1"
     }
  ]
}

to read it from the client side I use a OData query with expand - odata.sv/EntityA(1)?$expand=EntityB

Solution: To enable the above scenario on server side, I had to use navigation properties.

  • First we create two separate entities - EntityA and EntityB. Then we define the relationship by

    1. implementing getAssociation method and
    2. in EdmProvider setting navigation properties while defining EntityA
  • Next, at time of reading Entity(readEntity), we provide callback
    method by overriding 'retrieveFeedResult' for populating EntityB.

I have working POC for this. I can as well share this, if that is needed. Right now I am short of time, so just shared an overall approach. Hope this helps.

swemon
  • 5,840
  • 4
  • 32
  • 54