Как сериализовать свойство типа ICollection <T>при использовании Entity Framework - PullRequest
12 голосов
/ 21 сентября 2011

У меня есть класс, как показано ниже

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<SurveyResponse> SurveyResponses { get; set; }
    }

Приведенный выше код дает мне следующее исключение

Невозможно сериализовать элемент 'SurveyGenerator.Survey.Questions' типа 'System.Collections.Generic.ICollection

Когда я преобразую ICollection в список, он сериализуется должным образом

Поскольку это POCO Entity Framework, я не могу преобразовать ICollection в список

Ответы [ 5 ]

2 голосов
/ 09 ноября 2011

Судя по вашему классу, свойства ICollection определяют отношения внешнего ключа? Если это так, вы не хотели бы публично выставлять коллекции.

Например: если вы следуете руководству по передовым методам разработки моделей Entity Framework, то у вас будет отдельный класс с именем «Вопрос», который соединит два ваших класса вместе, что может выглядеть следующим образом:

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; }
}

Если бы это было так, вы вполне могли бы обойти круги, называя Вопрос -> Опрос -> ICollection -> Вопрос

У меня был похожий инцидент с использованием EF, MVC3 для реализации службы REST, и я не смог сериализовать объект ICollection <>, затем понял, что мне это не нужно, так как я все равно буду вызывать объект отдельно.

Обновленный класс для ваших целей будет выглядеть так:

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; }
}

Надеюсь, это поможет вам.

1 голос
/ 19 февраля 2015

Если вы не возражаете добавить ссылку на сборку System.Runtime.Serialization, вы можете использовать этот код, который будет сериализовать объект с ICollection без необходимости изменять реализацию объекта. Код ниже выводится в строку. Вы можете использовать поток так, как вам нравится.

    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());
        }
    }
1 голос
/ 23 февраля 2014

Измените ICollection на Список

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; }
}
0 голосов
/ 19 апреля 2018

Для меня проблема заключалась в отсутствии конструктора по умолчанию.Пример: список MyVar;// MyClass нужен открытый конструктор

0 голосов
/ 19 мая 2015

Я использовал решение Мэтью Меррифулла, и оно работает.

Поскольку я использую конструктор EF для создания сущностей, каждый раз, когда я обновляю свои модели, я теряю ручные изменения. Мне пришлось изменить * .tt, который используется для генерации моделей. Я отредактировал несколько строк:

   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));
}

Также проверьте эту статью на случай, если у вас возникнут проблемы с сериализацией http://geekswithblogs.net/danemorgridge/archive/2010/05/04/entity-framework-4-wcf-amp-lazy-loading-tip.aspx

...