Подтвердить что ты не робот

Сериализация свойства типа ICollection <T> при использовании Entity Framework

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

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 в List, он правильно сериализуется

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

4b9b3361

Ответ 1

Из внешнего вида вашего класса свойства 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 → Question

У меня был аналогичный инцидент с использованием 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; }
}

Я надеюсь, что это поможет вам.

Ответ 2

Измените ICollection <T> на Список <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; }
}

Ответ 3

Если вы не возражаете добавить ссылку на сборку 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());
        }
    }

Ответ 4

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

Поскольку я использую конструктор 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