As I mentioned in my last blog post , here are some samples of how to map your entity properties to Atom/custom markup in the atom:entry element. You can apply Friendly Feed mappings on the EDM entity types by adding attributes to the CSDL of the Entity Data Model . We will focus on the kinds of mappings and how to achieve them .
Pre-requisites 1. To edit the CSDL , you will need to open the EDM model in Xml view .To do this , right-click the EDM model (.EDMX file ) in Visual Studio and select “Open with”->”Xml Editor” . 2. Add a reference to this namespace in the <edmx:ConceptualModels> node of the CSDL section in the EDMX file : ex: xmlns:m2="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
1) Mapping to ATOM elements in the atom:entry payload : The EntityPropertyMapping (EPM) attribute has two constructors , one which binds the property to an Atom element in the feed , and another which binds the property to a custom element . We shall discuss the former in this section.
For ATOM Mappings , the EPM markup has the following attributes .
Lets proceed , using the same BlogPost type that we discussed last time . This is the EDM Markup for the type :
<EntityType Name="BlogPost"> <Key> <PropertyRef Name="BlogPostID" /> </Key> <Property Name="Lat" Type="Edm.Double" Nullable="false"/> <Property Name="Long" Type="Edm.Double" Nullable="false"/> <Property Name="Published" Type="Edm.DateTime" Nullable="false" /> <Property Name="BlogPostID" Type="Edm.Int32" Nullable="false" /> <Property Name="Title" Type="Edm.String" Nullable="true"/> <Property Name="Body" Type="Edm.String" Nullable="true" /> <Property Name="Author" Type="Edm.String" Nullable="true"/> <Property Name="PostURI" Type="Edm.String" Nullable="true" /> <Property Name="ContentSummary" Type="Edm.String" Nullable="true" /> <Property Name="IconUri" Type="Edm.String" Nullable="true"/> </EntityType>
1. Map the “Title” property of the BlogPost Entity type to the entry:title element
When decorating EDM types , the markup specifying the mapping goes on the property you are mapping , ex:
<Property Name="Title" Type="Edm.String" Nullable="true" m2:FC_TargetPath="SyndicationTitle" m2:FC_EpmContentKind="Plaintext" m2:FC_EpmKeepInContent="true" />
2. Map the “Author” property to entry:author element
This is what the markup would look like :
<Property Name="Author" Type="Edm.String" Nullable="true" m2:FC_TargetPath="SyndicationAuthorName" m2:FC_ContentKind="Plaintext" m2:FC_KeepInContent="true" />
As described in my previous blog post , you can map an Entity’s properties to the following atom:entry elements in the payload :
2) Mapping to non-ATOM/custom elements in the atom:entry payload :
For non-ATOM/custom Mappings , the EPM markup requires the following attributes.
The Xml Path syntax for custom mappings.
this syntax is very logical and looks like the following . Lets say that you wanted to map a property to a custom element in markup that looks like this :
<mycustomRoot xmlns=”http://www.mycustomFormat.org”> <customElement>property value goes here</customElement> </mycustomRoot>
and now , lets say that you wanted to map a property to a custom attribute of an element in markup that looks like this :
<me:mycustomRoot xmlns:me="http://www.georss.org.georss"> <me:customElement customAttribute="property value goes here"></me:customElement> </me:mycustomRoot>
for this example , m2:FC_TargetPath would be “mycustomRoot/customElement/@customAttribute” m2:FC_NsPrefix would be “me”. m2:FC_NsUri would be “http://www.mycustomFormat.org” m2:FC_KeepContent is subjective to whether you want to keep the property value in the <content> section or not.
A note , the complexity of your custom markup has a direct effect on the performance costs for Serialization/De-Serialization of the entity type . with this example , lets map the lat & long properties to geoRss markup ,which looks like this :
<geo:lat xmlns:geo="http://www.georss.org/georss">47.684</geo:lat> <geo:long xmlns:geo="http://www.georss.org/georss">-122.122</geo:long>
Final type definition looks like this :
<EntityType Name="BlogPost"> <Key> <PropertyRef Name="BlogPostID" /> </Key> <!-- map the Lat property to the <geo:lat> element --> <Property Name="Lat" Type="Edm.Double" Nullable="false" m2:FC_TargetPath="lat" m2:FC_NsUri="http://www.georss.org/georss" m2:FC_NsPrefix="geo" m2:FC_KeepContent="true" /> <!-- map the Long property to the <geo:long> element --> <Property Name="Long" Type="Edm.Double" Nullable="false" m2:FC_TargetPath="long" m2:FC_NsUri="http://www.georss.org/georss" m2:FC_NsPrefix="geo" m2:FC_KeepContent="true" /> <!-- Map the “Title” property of the BlogPost Entity type to the entry:title element --> <Property Name="Title" Type="Edm.String" Nullable="true" m2:FC_TargetPath="EpmSyndicationTitle" m2:FC_ContentKind="EpmPlaintext" m2:FC_KeepContent="true" /> <Property Name="Body" Type="Edm.String" Nullable="true" /> <!-- Map the “Author” property to entry:author element --> <Property Name="Author" Type="Edm.String" Nullable="true" m2:FC_TargetPath="EpmSyndicationAuthorName" m2:FC_ContentKind="EpmPlaintext" m2:FC_KeepContent="true" /> <Property Name="BlogPostID" Type="Edm.Int32" Nullable="false" /> <Property Name="Published" Type="Edm.DateTime" Nullable="false" /> <Property Name="PostURI" Type="Edm.String" Nullable="true" /> <Property Name="ContentSummary" Type="Edm.String" Nullable="true" /> <Property Name="IconUri" Type="Edm.String" Nullable="true"/> </EntityType>
Special cases
I . Complex type properties
[I’ll leave the type definitions as CLR types so that its easier to visualize the relations.] Consider the following model ,
public class Address { public long DoorNumber { get; set; } public string Street { get; set; } public int ZipCode { get; set; } } [DataServiceKey("CustomerID")] public class Customer { public int CustomerID { get; set; } public Address myAddress { get; set; } }
and lets say that you wanted to map the property Street of the complex type Address when accessed through the entity type “Customer” to the atom:title element ,
this can be achieved via setting the EpmSourcePath property to “Street” . In this case , the Epm markup would look like this :
<EntityType Name="Customer"> <!-- Map the Street property of the Address complex type to the entry:title element --> <Property Name="myAddress" Type="MyModelNamespace.Address" me:EpmSourcePath="Street" m2:FC_Atom="true" m2:FC_TargetPath="EpmSyndicationTitle" m2:FC_ContentKind="EpmPlaintext" m2:FC_KeepContent="true"/> <!-- other properties removed for brevity--> </EntityType>
II Mapping properties declared on base type Consider this data model :
[DataServiceKey("CustomerID")] public class Customer { public int CustomerID { get; set; } public Address myAddress { get; set; } public string BaseTypeField { get; set; } } public class DerivedCustomer : Customer { public string DerivedTypeField { get; set; } }
<!-- Map the "BaseTypeField" property of the base type "Customer" to the entry:title element --> <EntityType Name="DerivedCustomer" BaseType="MyModelNamespace.Customer" m2:FC_SourcePath="BaseTypeField" m2:FC_TargetPath="EpmSyndicationAuthorName" m2:FC_ContentKind="EpmPlaintext" m2:FC_KeepContent="true"> <!-- other properties removed for brevity--> </EntityType>
Considerations for location of EPM markup in EDM Schema
Use the following guidelines to decide where in the EDM Schema you should add the attribute for either ATOM or custom Mappings,
Hope you enjoyed this post about applying Friendly Feeds mappings to EDMdata models. The second part of this post will discuss more special cases in EDM Models and troubleshooting failing mappings and also a sample project for EDM Friendly Feeds Mappings.
PingBack from http://www.anith.com/?p=23990
Thank you for submitting this cool story - Trackback from DotNetShoutout
Phani, a member of the data services team, has continued his great series on Web Friendly Feeds with
Is there no way to simply have ADO.NET Data Services simply return a POX feed? As far as I'm aware, you can currently only return JSON and Atom. Is there a way to get ADO.NET Data Services to be fully plain-old-xml, so that the GET requests by default receive POX and when doing the HTTP INSERT/POST/DELETE, we send POX to the service?