开发者

How to Serialize property of type ICollection<T> while using Entity Framework

I have a class as shown below

public class Survey
    {
        public Survey()
        {
            SurveyResponses=new List<SurveyResponse>();
        }

        [Key]
        public Guid SurveyId { get; set; }
        public string SurveyName { get; set; }
        public string SurveyDescription { get; set; }
        public virtual ICollection<Question> Questions { get; set; }
        public virtual ICollection<SurveyRe开发者_开发问答sponse> SurveyResponses { get; set; }
    }

The above code gives me following exception

Cannot serialize member 'SurveyGenerator.Survey.Questions' of type 'System.Collections.Generic.ICollection

When i convert the ICollection to List it serializes properly

Since it is POCO of Entity Framework, i cannot convert ICollection to List


From the looks of your class the ICollection properties are defining foreign key relationships? If so, you wouldn't want to be publicly exposing the collections.

For example: If you are following the best practices guide for developing Entity Framework models, then you would have a separate class called "Question" which would wire up your two class together which might look like the following:

public class Question
{
    [Key]
    public int Id { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }

    public virtual Survey Survey { get; set; }
}

If this was the case, you could quite possibly go round in circles calling the Question -> Survey -> ICollection -> Question

I had a similar incident using EF, MVC3 to implement a REST service and couldn't serialize the ICollection<> object then realised I didn't need to as I would be calling the object separately anyway.

The updated class for your purposes would look like this:

public class Survey
{
    public Survey()
    {
        SurveyResponses=new List<SurveyResponse>();
    }

    [Key]
    public Guid SurveyId { get; set; }
    public string SurveyName { get; set; }
    public string SurveyDescription { get; set; }

    [XmlIgnore]
    [IgnoreDataMember]
    public virtual ICollection<Question> Questions { get; set; }

    [XmlIgnore]
    [IgnoreDataMember]
    public virtual ICollection<SurveyResponse> SurveyResponses { get; set; }
}

I hopes this helps you out.


Change the ICollection<T> to a List<T>

public class Survey
{
    public Survey()
    {
        SurveyResponses=new List<SurveyResponse>();
    }

    [Key]
    public Guid SurveyId { get; set; }
    public string SurveyName { get; set; }
    public string SurveyDescription { get; set; }
    public virtual List<Question> Questions { get; set; }
    public virtual List<SurveyResponse> SurveyResponses { get; set; }
}


If you don't mind adding a reference to the assembly System.Runtime.Serialization, you can utilize this code which will serialize an object with ICollection without needing to change the object's implementation. The code below is outputting to string. You can use the stream however you'd like.

    private string ConvertClassToXMLString<T>(T classObject)
    {
        using (var stream = new MemoryStream())
        {
            var serializer = new DataContractSerializer(classObject.GetType());
            serializer.WriteObject(stream, classObject);

            return Encoding.UTF8.GetString(stream.ToArray());
        }
    }


I used Matthew Merryfull solution and it works.

Since I am using EF designer for entity generation each time I update my models I would loose manual changes. I had to change *.tt which is used for generation of models. I edited few lines:

   public string NavigationProperty(NavigationProperty navigationProperty)
{
var enbleWebService = string.Empty;
if(navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ){
enbleWebService = string.Format("[XmlIgnore]{0}[IgnoreDataMember]{0}", Environment.NewLine);
}
    var endType = _typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType());
    return string.Format(
        CultureInfo.InvariantCulture,
        "{5} {0} {1} {2} {{ {3}get; {4}set; }}",
        AccessibilityAndVirtual(Accessibility.ForProperty(navigationProperty)),
        navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType,
        _code.Escape(navigationProperty),
        _code.SpaceAfter(Accessibility.ForGetter(navigationProperty)),
        _code.SpaceAfter(Accessibility.ForSetter(navigationProperty)),
         _code.Escape(enbleWebService));
}

 public string NavigationProperty(NavigationProperty navigationProperty)
{
var enbleWebService = string.Empty;
if(navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ){
    enbleWebService = string.Format("[XmlIgnore]{0}[IgnoreDataMember]{0}", Environment.NewLine);
}
    var endType = _typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType());
    return string.Format(
        CultureInfo.InvariantCulture,
        "{5} {0} {1} {2} {{ {3}get; {4}set; }}",
        AccessibilityAndVirtual(Accessibility.ForProperty(navigationProperty)),
        navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType,
        _code.Escape(navigationProperty),
        _code.SpaceAfter(Accessibility.ForGetter(navigationProperty)),
        _code.SpaceAfter(Accessibility.ForSetter(navigationProperty)),
         _code.Escape(enbleWebService));
}

Also check this article in case you run into problem with serialization http://geekswithblogs.net/danemorgridge/archive/2010/05/04/entity-framework-4-wcf-amp-lazy-loading-tip.aspx


For me the issue was not having a default constructor. Example: List MyVar; // MyClass needs a public constructor

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜