XMLserializer, Entity Framework: невозможно сериализовать член типа ICollection, см. Внутреннее исключение для получения дополнительных сведений.

Я хочу сопоставить элементы XML в моей таблице базы данных (используя Entity Framework):

var xmlSerializer = new XmlSerializer(typeof(Participant), new XmlRootAttribute("participant"));
var participant = (Participant)xmlSerializer.Deserialize(new StringReader(content));

У меня есть таблица участников, к которой я могу получить доступ,

[XmlRoot("participant", Namespace = "")]
    public partial class Participant
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage",     "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public Participant()
        {
            this.GroupParticipant = new HashSet<GroupParticipant>();
            this.ParticipantAddress = new HashSet<ParticipantAddress>();
            this.ParticipantPublisher = new HashSet<ParticipantPublisher>();
            this.ParticipantJob = new HashSet<ParticipantJob>();
            this.ParticipantProvider = new HashSet<ParticipantProvider>();
        }
        [XmlElement("firstName")]
        public string FirstName { get; set; }

        [XmlElement("lastName")]
        public string LastName { get; set; }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        //[XmlElement("address")]
        //[XmlElement("address")]
        //[XmlArray("HashSet<ParticipantAddress>"), XmlElement("address")]
        //[XmlArrayItem("ICollection<ParticipantAddress>")]
        //[XmlAttribute(DataType = "ICollection<ParticipantAddress>",  AttributeName = "address")]

[XmlElement("address", typeof(List<ParticipantAddress>))]
        public virtual ICollection<ParticipantAddress> ParticipantAddress { get; set; }
}

ParticipantAddress - ICollection:

[Serializable]
    [XmlInclude(typeof(HashSet<ParticipantAddress>))]
    public partial class ParticipantAddress
    {
        public int ParticipantAddressId { get; set; }
        public int ParticipantId { get; set; }

        [XmlElement("city")]
        public string City { get; set; }

        [XmlElement("state")]
        public string State { get; set; }

        [XmlElement("zipCode")]
        public string ZipCode { get; set; }

        public virtual Participant Participant { get; set; }
    }

Исключение говорит:

{"Произошла ошибка при отображении типа 'x.Participant'."}

Мое внутреннее исключение говорит:

{"Невозможно сериализовать член 'xParticipant.ParticipantAddress' типа 'System.Collections.Generic.ICollection`1 [[x.ParticipantAddress, APS.Data.BatchInterface, Version = 1.0.0.0, Culture = нейтральный, PublicKeyToken = null]]' , подробнее см. внутреннее исключение. "}

Я читаю XML с помощью streamReader.

я пытался

  • [XMLArray]
  • Изменение ICollection на список
  • сделать класс сериализуемым

Есть ли другой способ решить эту проблему или какие-либо примеры, связанные с моим вопросом или любыми изменениями, которые мне нужно реализовать в моем коде?


person Riddhi    schedule 10.12.2015    source источник


Ответы (5)


ICollection не сериализуем.
- Вы можете использовать DTO.
- Вы можете изменить тип коллекции (например, с помощью List ‹>), а с помощью атрибутов сериализации XML избежать циклических ссылок и / или отключить ленивую загрузку (например, использовать нетерпеливую загрузку используя метод Include), иначе вы можете сериализовать всю базу данных.

person bubi    schedule 10.12.2015
comment
Спасибо за вашу помощь. Я создал регион и изменил тип коллекции ICollection ‹› на List ‹›, потому что ICollection - это интерфейс, а интерфейсы не сериализуемы. Но List ‹› - это класс, и этот класс реализует все указанные ниже интерфейсы: IList ‹T›, ICollection ‹T›, IList, ICollection, IReadOnlyList ‹T›, IReadOnlyCollection ‹T›, IEnumerable ‹T›, IEnumerable. - person Riddhi; 14.12.2015

Эта проблема возникает из-за свойств virtual. Вы пытаетесь сериализовать класс, который имеет ссылку на другой класс, который имеет ссылку на первый класс, который ... бесконечный цикл.

Если вы хотите сериализовать сущность, лучшее, что вы можете сделать, это использовать класс DTO, который используется только для экспорта ваших данных. В этих классах у вас не может быть виртуальных свойств, но вы можете включить объекты DTO вашего ParticipantAddress.

Другая вещь, которую вы можете попробовать, если нет необходимости в сериализации в XML, - это использовать пакет Newtonsoft.Json для сериализации сущностей. В пакете есть несколько опций для работы с навигационными свойствами.

person Alexander Derck    schedule 10.12.2015

Я создал регион и изменил ICollection ‹> на List‹>, потому что

ICollection - это интерфейс, и интерфейсы не сериализуемы.

Но List ‹> - это класс, и этот класс реализует все указанные ниже интерфейсы: IList, ICollection, IList, ICollection, IReadOnlyList, IReadOnlyCollection, IEnumerable, IEnumerable.

Я сохранил как Icollection, так и List и поместил [XmlIgnore] в ICollection.

    [XmlRoot("participant", Namespace = "")]
    public partial class Participant
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public Participant()
        {
            this.GroupParticipantList = new List<GroupParticipant>();
            this.ParticipantAddressList = new List<ParticipantAddress>();
            this.ParticipantPublisherList = new List<ParticipantPublisher>();
            this.ParticipantJobList = new List<ParticipantJob>();
            this.ParticipantProviderList = new List<ParticipantProvider>();
        }

        [XmlElement("firstName")]
        public string FirstName { get; set; }

        [XmlElement("lastName")]
        public string LastName { get; set; }

        [XmlIgnore]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<ParticipantAddress> ParticipantAddress { get; set; }

        #region Custom properties

        [XmlElement("address")]
        public virtual List<ParticipantAddress> ParticipantAddressList { get; set; }

        #endregion
    }

Но с этим вариантом у меня возникает другая проблема: если я внесу одно изменение в свою базу данных SQL и обновлю модель из базы данных, то я потеряю реализованный вручную код, как и все предложения XML в этом коде. .

person Riddhi    schedule 14.12.2015

Я ответил на это в статье ниже, чтобы добавить [System.Xml.Serialization.XmlIgnore] в шаблон entity.tt

Запретить сериализацию свойства

person Michael Goldshmidt    schedule 25.10.2019

У меня был похожий инцидент с использованием EF для реализации веб-службы, когда я не мог сериализовать объект ICollection ‹›. Надеюсь, это вам поможет.

public class User
{
    public User()
    {
        sessions = new HashSet<Session>();
    }

    public int Id { get; set; }
    public string Name { get; set; }

    [XmlIgnore]
    [IgnoreDataMember]
    public virtual ICollection<Session> sessions { get; set; }
}


public class Session
{
    public int Id { get; set; }
    public Datetime start_dtime{ get; set; }
    public Datetime end_dtime{ get; set; }

    public virtual User user{ get; set; }
}
person Shahid72    schedule 17.02.2021