Merge complex types and entity types
Applies To: # OData core lib v7 supported OData Core Lib V7
In ODataLib 7.0, we merged the public APIs for serializing/deserializing complex values and entities. We did this because complex type and entity type are becoming more and more similar in the protocol, but we continue to pay overhead to make things work for both of them. Since the only really fundamental differences between complex type and entity type at this point are the presence of a key and media link entries, we thought it was best to merge them and just deal with the differences.
We followed the existing implementation of serializing/deserializing entity instances for both entity instances and complex instances, and the implementation of serializing/deserializing entity collections for both entity collections and complex collections. This page will provide some simple sample code about how to write these kinds of payload.
Public APIs used to store complex/entity instances
ODataResource
class is used to store information of an entity instance or a complex instance.
ODataResourceSet
class is used for both a collection of entity or a collection of complex.
ODataNestedResourceInfo
class is used for both navigation property and complex property. For complex property, this class will be used to store the name of the complex property and a Boolean to indicate whether this property is a single instance or a collection.
For other Public APIs, you can refer to the Breaking changes about Merge Entity and Complex.
Model
Suppose we have a model, in following sections, we will explain how to write/read a complex property or a collection complex property.
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="https://docs.oasis-open.org/odata/ns/edmx">
<edmx:DataServices>
<Schema Namespace="SampleService" xmlns="https://docs.oasis-open.org/odata/ns/edm">
<ComplexType Name="Location" OpenType="true">
<Property Name="Address" Type="Edm.String" Nullable="false" />
<Property Name="City" Type="Edm.String" Nullable="false" />
</ComplexType>
<EntityType Name="Person" OpenType="true">
<Key>
<PropertyRef Name="UserName" />
</Key>
<Property Name="UserName" Type="Edm.String" Nullable="false" />
<Property Name="HomeAddress" Type="SampleService.Location" />
<Property Name="OtherAddresses" Type="Collection(SampleService.Location)" />
</Property>
</EntityType>
<EntityContainer Name="DefaultContainer">
<EntitySet Name="People" EntityType="SampleService.Person" />
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
Write a top level complex instance
In order to write the complex property payload, we need to create an ODataWriter
first. ODataLib provides ODataMessageWriter.CreateODataResourceWriter
to create the writer.
IODataResponseMessage message;
IEdmStructuredType complexType;
// Initialize the message and the complexType;
// message = ...;
// complexType = ...;
var settings = new ODataMessageWriterSettings { Version = ODataVersion.V4 };
settings.ODataUri = https://localhost/odata/;
ODataMessageWriter messageWriter = new ODataMessageWriter(message, settings, model);
var writer = messageWriter.CreateODataResourceWriter(null, complexType);
Then, we can write a complex property just like writing an entity by using WriteStart
and WriteEnd
.
ODataResource complexResource = new ODataResource()
{
Properties = new ODataProperty[]
{
new ODataProperty { Name = "Address", Value = "Zixing Road" },
new ODataProperty { Name = "City", Value = "Shanghai" }
}
};
writer.WriteStart(complexResource);
writer.WriteEnd();
If we want to write a complex collection property, we can use CreateODataResourceSetWriter
and write the complex collection property.
writer = messageWriter.CreateODataResourceSetWriter(null, complexType /* item type */);
ODataResourceSet complexCollection = new ODataResourceSet()
ODataResource complexResource = new ODataResource()
{
Properties = new ODataProperty[]
{
new ODataProperty { Name = "Address", Value = "Zixing Road" },
new ODataProperty { Name = "City", Value = "Shanghai" }
}
};
writer.WriteStart(complexCollection); // write the resource set.
writer.WriteStart(complexResource); // write each resource.
writer.WriteEnd(); // end the resource.
writer.WriteEnd(); // end the resource set.
Write a complex property in an entity instance
To write an entity with a complex property, we can create the ODataWriter
for the entity by calling CreateODataResourceWriter
, and then write the entity. we write the complex property just as writing a navigation property.
- Write the property name of the complex property by
WriteStart(ODataNestedResourceInfo nestedResourceInfo)
- Write the complex instance by
WriteStart(ODataResource resource)
. WriteEnd()
for each part.
Sample:
// Init the entity instance.
ODataResource entityResource = new ODataResource()
{
Properties = new ODataProperty[]
{...}
}
// Create the ODataNestedResourceInfo for the HomeAddress property.
ODataNestedResourceInfo homeAddressInfo = new ODataNestedResourceInfo() { Name = "HomeAddress", IsCollection = false };
ODataResource complexResource = new ODataResource()
{
Properties = new ODataProperty[]
{
new ODataProperty { Name = "Address", Value = "Zixing Road" },
new ODataProperty { Name = "City", Value = "Shanghai" }
}
};
writer.WriteStart(homeAddressInfo); // write the nested resource info.
writer.WriteStart(complexResource); // write then resource.
writer.WriteEnd(); // end the resource.
writer.WriteEnd(); // end the nested resource info
To write a complex collection property in an entity, we need to set ODataNestedResourceInfo.IsCollection
is set to true, and then write the resource set.
// Init the entity instance.
ODataResource entityResource = new ODataResource()
{
Properties = new ODataProperty[]
{...}
}
// Create the ODataNestedResourceInfo for the OtherAddresses property.
ODataNestedResourceInfo otherAddressesInfo = new ODataNestedResourceInfo() { Name = "OtherAddresses", IsCollection = true };
ODataResourceSet complexCollection = new ODataResourceSet()
ODataResource complexResource = new ODataResource()
{
Properties = new ODataProperty[]
{
new ODataProperty { Name = "Address", Value = "Zixing Road" },
new ODataProperty { Name = "City", Value = "Shanghai" }
}
};
writer.WriteStart(entityResource); // write the entity instance.
writer.WriteStart(otherAddressesInfo); // write the nested resource info.
writer.WriteStart(complexCollection); // write the resource set.
writer.WriteStart(complexResource); // write each resource.
writer.WriteEnd(); // end the resource.
writer.WriteEnd(); // end the resource set.
writer.WriteEnd(); // end the nested resource info
writer.WriteEnd(); // end the entity instance.
Developers can follow the same way to write a nested complex property in a complex instance.
Write complex or entity instances in Uri parameters
To write an entity (or a complex) instance or a collection of entity (or a collection of complex) in Uri parameters, ODataLib provides ODataMessageWriter.CreateODataUriParameterResourceWriter
and ODataMessageWriter.CreateODataUriParameterResourceSetWriter
to create the ODataWriter
. Then, you can follow the same sample code in the above two sections to write the related parameters.
Read a top level complex instance
To read a complex (or an entity) instance, ODataLib provides ODataMessageReader.CreateODataResourceReader
to create the ODataReader
.
IODataResponseMessage message;
IEdmStructuredType complexType;
// Initialize the message and the complexType;
// message = ...;
// complexType = ...;
var settings = new ODataMessageReaderSettings { EnableMessageStreamDisposal = true };
ODataMessageReader messageReader = new ODataMessageReader(message, settings, model);
var reader = messageReader.CreateODataResourceReader(null, complexType);
Then, developers can read the complex (or entity) instance, nested complex ( or complex collection) properties or navigation properties.
while (reader.Read())
{
switch (reader.State)
{
case ODataReaderState.ResourceEnd:
// reader.Item is a resource which reprensents the complex instance or its nested resources
// 1. nested complex instance of a complex property
// 2. nested complex instances of a complex collection property
// 3. entity instances or a navigation property.
complex = reader.Item as ODataResource;
break;
case ODataReaderState.ResourceSetEnd:
// reader.Item is a resource set which represents a collection of complex or entity.
// 1. nested complex collection
// 2. navigated entity collection
complex = reader.Item as ODataResourceSet;
break;
case ODataReaderState.NestedResourceInfoEnd:
// reader.Item is a the nested resource info which represents a complex property, a complex collection property or a navigation property.
complex = reader.Item as ODataNestedResourceInfo;
break;
default:
break;
}
}
if this reader is created for an entity type, the same code can be used to read an entity instance.
Read a top level complex collection
To read a complex collection ( or an entity collection) , ODataLib provides ODataMessageReader.CreateODataResourceSetReader
to create the ODataReader
.
var reader = messageReader.CreateODataResourceSetReader(null, complexType);
while (reader.Read())
{
switch (reader.State)
{
case ODataReaderState.ResourceEnd:
// reader.Item is a resource which reprensents the complex instance or its nested resources
// 0. the top level complex instance.
// 1. nested complex instance of a complex property.
// 2. nested complex instances of a complex collection property.
// 3. entity instances or a navigation property.
complex = reader.Item as ODataResource;
break;
case ODataReaderState.ResourceSetEnd:
// reader.Item is a resource set which represents a collection of complex or entity.
// 0. the top level complex collection.
// 2. netsed complex collection.
// 2. navigated entity collection.
complex = reader.Item as ODataResourceSet;
break;
case ODataReaderState.NestedResourceInfoEnd:
// reader.Item is a the nested resource info which represents a complex property, a complex collection property or a navigation property.
complex = reader.Item as ODataNestedResourceInfo;
break;
default:
break;
}
}
if this reader is created for an entity collection, the same code can be used to read an entity collection.
Read complex or entity instances in Uri parameters
To read an entity (or a complex) instance or a collection of entity (or a collection of complex) in Uri parameters, ODataLib provides ODataMessageReader.CreateODataUriParameterResourceReader
and ODataMessageReader.CreateODataUriParameterResourceSetReader
to create the ODataReader
. Then, you can follow the same sample code in the above two sections to read the related parameters.
Feedback
https://aka.ms/ContentUserFeedback.
Coming soon: Throughout 2024 we will be phasing out GitHub Issues as the feedback mechanism for content and replacing it with a new feedback system. For more information see:Submit and view feedback for