none
DataContractJsonSerializer and Entity Framework relations RRS feed

  • Question

  • Hi,

     

    I have a model that holds 2 related entities - Person and Addresses (multiple addresses per person).

     

    When I load a person with his addressed and serialize them using DataContractJsonSerializer, the json string only holds the Person data and not the Addresses data.

     

    If I try to use Asp.Net Ajax JavaScriptSerializer, I am able to serialize both the person and the addressed, but if I try to deserialize it with DataContractJsonSerializer, I only get the Person and not the Addresses.

     

    From what I found, the reason is that the Addresses property doesn't have a DataMemberAttribute and doesn't have a set method for the property.

     

    I tried to add the attribute and the code to the generated code, and managed to make the serializer work, but before I write my own class-generator code for entity framework, I'd like to know if anyone heard of this problem and can solve it with the given generated classes.

     

    Thanks in advance,

    Ido Flatow.

    Thursday, July 3, 2008 1:26 PM

Answers

  • I used the following code to look into this:

           

    Code Snippet

    private static T DataContractJson2Serializer<T>(T obj)

            {

                DataContractJsonSerializer dcSer = new DataContractJsonSerializer(obj.GetType());

                MemoryStream memoryStream = new MemoryStream();

                dcSer.WriteObject(memoryStream, obj);

     

     

    The line in bold threw the following exception:

     

    The type 'ForumBlogReproModel.Person' cannot be serialized to JSON because its IsReference setting is 'True'. The JSON format does not support references because there is no standardized format for representing references. To enable serialization, disable the IsReference setting on the type or an appropriate parent class of the type.

      

    From this it looks like:

     

    1)      Json serialization of graphs is not supported by design

    2)      Customers needing to do Json serialization will need to set manually this attribute to false for reference properties in the code-gen’d classes.

     

    I have sent a request to the Astoria team to gather more information from them, but wanted to give you an update to let youi know we are working on this. I also noticed another forum post raising the same issue.

     

    Tuesday, July 8, 2008 10:54 AM

All replies

  • Doesn't sound like you are using the SP1 bits. This support was added in SP1. I've created a similar model using the designer and here's what I'm seeing in the code-gen'd Person class for the Address property.

     

    Code Snippet

    [global::System.Data.Objects.DataClasses.EdmRelationshipNavigationPropertyAttribute("ForumBlogReproModel", "FK_Address_Person", "Address")]

    [global::System.Xml.Serialization.XmlIgnoreAttribute()]

    [global::System.Xml.Serialization.SoapIgnoreAttribute()]

    [global::System.Runtime.Serialization.DataMemberAttribute()]

    public global::System.Data.Objects.DataClasses.EntityCollection<Address> Address

    {

    get

    {

    return ((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.GetRelatedCollection<Address>("ForumBlogReproModel.FK_Address_Person", "Address");

    }

    set

    {

    if ((value != null))

    {

    ((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.InitializeRelatedCollection<Address>("ForumBlogReproModel.FK_Address_Person", "Address", value);

    }

    }

    }

     

    I loaded a person with 2 addresses, serialized with DataContractSerializer and rehydrated to a new object, and both addresses where there. If you are using SP1, please send your related CSDL content
    Thursday, July 3, 2008 3:18 PM
  • You're right.

     

    I've upgraded to SP1 Beta 1 (which means i'll probably have to format my pc when the RTM is released) and it works.

     

    Why haven't the people in the ADO.NET Team blog written about this bug fix in their "what's new in the sp1 beta" post ? I think it's a rather important fix that should be mentioned.

     

    http://blogs.msdn.com/adonet/archive/2008/05/12/what-s-new-in-the-sp1-beta.aspx

     

    Thanks again,

    Ido.

    Saturday, July 5, 2008 8:28 AM
  •  

    Hi Patrick,

     

    Apparently I was too hasty to announce it works. The DataMember attribute was indeed added to the property and the setter was added too, but another bug appeared - I can no longer use DataContractJsonSerializer.

     

    Apparently, a new addition was adding IsReference=true to all data contracts (probably for many-to-1 relationships), which made the serializer add a z:id attribute to the entities. This addition makes the DataContractJsonSerializer throw an exception "Encountered unexpected prefix z...".

     

    So the SP1 actually ruined my work, because before I was able to workaround the datamember problem by writing my own properties for collections, but now, with the newly isreference property, I can no longer serialize any of the entities to json.

     

    Any thoughts ?

     

    Ido.

    Sunday, July 6, 2008 12:29 PM
  • I used the following code to look into this:

           

    Code Snippet

    private static T DataContractJson2Serializer<T>(T obj)

            {

                DataContractJsonSerializer dcSer = new DataContractJsonSerializer(obj.GetType());

                MemoryStream memoryStream = new MemoryStream();

                dcSer.WriteObject(memoryStream, obj);

     

     

    The line in bold threw the following exception:

     

    The type 'ForumBlogReproModel.Person' cannot be serialized to JSON because its IsReference setting is 'True'. The JSON format does not support references because there is no standardized format for representing references. To enable serialization, disable the IsReference setting on the type or an appropriate parent class of the type.

      

    From this it looks like:

     

    1)      Json serialization of graphs is not supported by design

    2)      Customers needing to do Json serialization will need to set manually this attribute to false for reference properties in the code-gen’d classes.

     

    I have sent a request to the Astoria team to gather more information from them, but wanted to give you an update to let youi know we are working on this. I also noticed another forum post raising the same issue.

     

    Tuesday, July 8, 2008 10:54 AM
  •  

    Thank you for you answer.

     

    It's quite strange that by design JSON serialization doesn't support graph serialization and XML serialization does support it - both are hierarchical "infoset" representation of objects, I would have guessed that a basic issue like namespaces and referencial data would get into JSON.

     

    In the meanwhile, I found a workaround using JavaScriptSerializer to serialize objects and DataContractJsonSerializer to deserialize them.

    Tuesday, July 8, 2008 8:22 PM
  •  

    Interestingly, I ended up doing the exact same thing while troubleshooting the same problem and then I found this post.  I have been trying to get the ExtJs framework to talk JSON to an EF entity data model and have had limited success so far. 

     

    I can:

     

    - use "application/json" in an ADO.NET Data Services request header and that works like a charm.  The only problem is, you are stuck with the EDM and if you want to return an additional property that's calculated based on EDM object properties, ADO.NET Data Services doesn't allow you to do that. 

    - use WCF to return the result of a Linq to Entities query but I can only serialize to XML, not JSON, as explained in the above replies.  I find JSON much easier to work with in JavaScript.

    - copy properties from Linq to Entities query results to non-EDM DataContract object and return as JSON via WCF.  Too much to maintain.

    - use JavaScriptSerializer only on objects that don't contain circular references.

     

    Can anybody explain how ADO.NET Data Services can serialize an EDM object to JSON without any problem but it can't be done with DataContractJsonSerializer?  What mechanism does ADO.NET Data Services use?

     

    Thanks for any help.

    Thursday, August 28, 2008 6:24 PM
  • ADO.net Data Services implemented their own Json serializer

    Friday, August 29, 2008 1:47 AM
  • We have the same problem too.

    We use ajax and asp.net and EF to implement our aplication and we want to serialize object as JSON.

    WCF can't do it becuase of [IsRefrence = true] problem and JavaScriptSerializer can't serialize EF object because

    of circular reference.

    when we make object's reference type property private,  JavaScriptSerializer can serialize them but can't deserialize them

    because of EntityCollection, with error 'Can't convert List<> type to EntityCollection. 

    We do some workaround to make EntityCllection property private and write our property that return List<> type

    insted of EntityCollection (that I think it's not nice because I have to modify all generated class).

    So now JavaScriptSerializer can deserialize them to EF object but still there is another problem.

    The problem is EntityKey type hold all Key and thire value in a Dictionary <string,object>

    When EF object Deserialize from JSON , all keys of type GUID Deserialize to String.

     

    We planed to use WCF (and svc webservice) but we could not use it becuse it can't serialize object to JSON.

    So we get to use asmx web service but we still have problem.

     

    at the end I have to regenerate all EntityKey type after I get EF object in server side but it is not nice too.

     

    Any Idea that why WCF dose not support JSON serialize for EF object ?

    We have VS2008 with SP1 instaled.

     

    Tanks in advance

    Mohsen

    Thursday, September 11, 2008 7:43 AM