Попытка обновить сущность с использованием EF и отправить ее с использованием свойства WCF - вызывает исключение в сценарии обновления

Я пытаюсь отправить объект с помощью WCF. Объект извлекается из БД с помощью EF.

Это исключение, которое я получаю:

введите описание изображения здесь

Это происходит только в сценарии обновления. Вставка отлично работает.
Отслеживая ошибку, я обнаружил, что проблема связана с недавно созданной коллекцией (называемой Travelers).

Вот что происходит, когда я пытаюсь посмотреть его значение во время выполнения, после обновления, перед отправкой обновленного объекта WCF:

введите описание изображения здесь

В этом объявлении свойства класса (я пробовал раскомментировать атрибут DataMember, но он не работал):

[DataContract]
public class Travel : InsuredObject, ISaleEntity, ICloneable
{    
    //[DataMember]
    public virtual ICollection<Traveler> Travelers { get; set; } 
    ...  

Я читал, что this.Configuration.ProxyCreationEnabled = false; и/или this.Configuration.LazyLoadingEnabled = false; могут это исправить, но я не могу изменить их по причинам, выходящим за меня, и даже когда я пытался играть с ними, у меня есть другие исключения...

Дополнительный код:
Метод обновления:

public virtual TEntity CreateAndUpdate(int saleId, TEntity entity) {
    var context = ((IObjectContextAdapter)this.Context).ObjectContext;

    var objBaseSet = context.CreateObjectSet<TBase>();

    var entityBaseKey = context.CreateEntityKey(objBaseSet.EntitySet.Name, entity);
    Object foundBaseEntity;
    var baseExists = context.TryGetObjectByKey(entityBaseKey, out foundBaseEntity);

    entity.Id = saleId;

    if (!baseExists) {
        this.GetDbSet<TEntity>().Add(entity); 
    }

    this.objectContext.SaveChanges();

    return entity;
}  

Извлечение содержащего объекта перед обновлением:

public virtual IQueryable<TEntity> GetAll(Expression<Func<TEntity, bool>> where, bool brutalRefresh = false) {

    IQueryable<TEntity> retObj = this.GetDbSet<TEntity>();
    if (where != null) {
        retObj = retObj.Where(where);
    }

    if (brutalRefresh) {
        var context = ((IObjectContextAdapter)this.Context).ObjectContext;
        context.Refresh(RefreshMode.StoreWins, retObj);
    }

    return retObj;
}

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

Traveler Класс (полностью):

 [DataContract]
    public class Traveler : ISaleEntity, ICloneable
    {
        [DataMember]
        public int Id { get; set; }

        [DataMember]
        public string FirstName { get; set; }

        [DataMember]
        public string LastName { get; set; }

        [DataMember]
        public string IDNumber { get; set; }

        [DataMember]
        public DateTime? BirthDate { get; set; }

        [DataMember]
        public virtual ICollection<SelectedCoverage> SelectedCoverages { get; set; }

        [NotMapped]
        public List<MedicalQuestionnaireAnswer> MedicalQuestionnaireAnswers
        {
            get
            {
                if (string.IsNullOrWhiteSpace(DBMedicalQuestionnaireAnswers))
                    return new List<MedicalQuestionnaireAnswer>();

                return DBMedicalQuestionnaireAnswers.Split(',')
                    .Select(c => (MedicalQuestionnaireAnswer)int.Parse(c)).ToList();
            }
            set { DBMedicalQuestionnaireAnswers = string.Join(",", value.Select(m => (int)m)); }
        }

        [NotMapped]
        public Genders Gender
        {
            get { return (Genders)DBGender; }
            set { DBGender = (int)value; }
        }

        /// <summary>
        /// NOTE! Do not use this property directly! use MedicalQuestionnaireAnswers instead
        /// </summary>
        [DataMember]
        public string DBMedicalQuestionnaireAnswers { get; set; }

        /// <summary>
        /// NOTE! Do not use this property directly! use Gender instead
        /// </summary>
        [DataMember]
        public int DBGender { get; set; }

        public object Clone()
        {
            Traveler traveler = new Traveler();
            traveler.FirstName = this.FirstName;
            traveler.LastName = this.LastName;
            traveler.IDNumber = this.IDNumber;
            traveler.BirthDate = this.BirthDate;
            traveler.DBMedicalQuestionnaireAnswers = this.DBMedicalQuestionnaireAnswers;
            traveler.Gender = this.Gender;
            if (this.SelectedCoverages != null)
            {
                traveler.SelectedCoverages = this.SelectedCoverages.Select(sc => (SelectedCoverage)sc.Clone()).ToList();
            }

            return traveler;
        }
    }

    public static class TravelerExtension
    {

        /// <summary>
        /// copy all the property except from the id and src defualt values
        /// </summary>
        /// <param name="dbTraveler"></param>
        /// <param name="src"></param>
        public static void CopyTravelerProperties(this Traveler target, Traveler src)
        {
            target.FirstName = src.FirstName;
            target.LastName = src.LastName;
            target.IDNumber = src.IDNumber;
            target.BirthDate = src.BirthDate;
            target.DBMedicalQuestionnaireAnswers = src.DBMedicalQuestionnaireAnswers;
            target.DBGender = src.DBGender;
            target.SelectedCoverages.CopySelectedCoveragesProperties(src.SelectedCoverages);
        }
    }

    public static class TravelersExtension
    {

        /// <summary>
        /// copy all the property except from the id and src defualt values
        /// </summary>
        /// <param name="dbTravelers"></param>
        /// <param name="src"></param>
        public static void CopyTravelersProperties(this ICollection<Traveler> target, ICollection<Traveler> src)
        {

            List<int> allTravelersIdsSrc = src.Select(t => t.Id).ToList();

            // remove ids exist target and not in src 
            target.ToList().RemoveAll(t => allTravelersIdsSrc.Contains(t.Id));


            target = target ?? new List<Traveler>();
            foreach (Traveler srcTraveler in src)
            {
                var targetTraveler = target.FirstOrDefault(targetTrv => srcTraveler.Id != 0 && targetTrv.Id == srcTraveler.Id);
                // if not exist traveler with target traveler id in db
                if (targetTraveler == null)
                {
                    // add srcTraveler to target
                    target.Add(srcTraveler);
                }
                else
                {
                    targetTraveler.CopyTravelerProperties(srcTraveler);
                }

            }
        }
    }

Дополнительная информация:
Исключение непосредственного окна не возникает, если вы вызываете ToList(), прежде чем пытаться получить значение в непосредственном окне. Однако сама проблема сохраняется.

Попытка прокомментировать атрибут [DataMember]:

public virtual ICollection<SelectedCoverage> SelectedCoverages { get; set; }

в классе Traveler не повлиял.

Исключение:

введите описание изображения здесь

Дополнительная информация 2:

Существует только 1 объект, который вызывает исключение:

public class Quote : ISaleEntity, ICloneable {      
    ...
        [DataMember]
        public virtual Travel Travel { get; set; } 
    ...   

Когда я изменяю выше [DataMember] на [IgnoreDataMember] - исключение.

Я установил все свойства этого класса в [IgnoreDataMember]

[DataContract]
    public class Travel : InsuredObject, ISaleEntity, ICloneable
    {
         [IgnoreDataMember]
        //[DataMember]
        public bool? IsFromIsrael { get; set; }

        [IgnoreDataMember]
        //[DataMember]
        public virtual ICollection<Traveler> Travelers { get; set; }

        [IgnoreDataMember]
        public virtual Quote Quote { get; set; }

          [IgnoreDataMember]
        //[DataMember]
        [NotMapped]
        public List<int> DestinationsCodes
        {
            get
            {
                if (string.IsNullOrWhiteSpace(DBDestinationsCodes))
                    return new List<int>();

                return DBDestinationsCodes.Split(',').Select(c => int.Parse(c)).ToList();
            }

            set { DBDestinationsCodes = string.Join(",", value); }
        }

        /// <summary>
        /// NOTE! Do not use this property directly! use DestinationsCodes instead
        /// </summary>
             [IgnoreDataMember]
        //[DataMember]
        public string DBDestinationsCodes { get; set; }
        ...  

Но исключение все же происходит. Вероятно, из-за класса, который этот класс наследует от:

[DataContract]
    [KnownType(typeof(Vehicle))]
    [KnownType(typeof(Apartment))]
    [KnownType(typeof(Travel))]
    public class InsuredObject : ISaleEntity, ICloneable {
        [Key]
        [DataMember]
        public int Id { get; set; }

        [DataMember]
        public int? OwnerTypeId { get; set; }


        //navigation property

        [DataMember]
        public bool? HasShiabud { get; set; }

        [DataMember]
        [IgnoreDataMember]
        public virtual Shiabud Shiabud { get; set; }

        //[NotMapped]
        //public virtual Proposal Proposal { get; set; }

        //[DataMember]
        [IgnoreDataMember]
        public virtual ICollection<Coverage> Coverages { get; set; }  
        ...

Итак, как я могу отправить этот объект через WCF?

Ответ 1

Можете ли вы поделиться частью своего кода с контекстом EF, который обновляет БД?

Из сообщения об ошибке я понимаю, что это не WCF, который играет в трюки. Скорее, похоже, что объект EF ObjectContent был удален к моменту применения ваших изменений (метод SaveChanges()). Это может произойти, если вы поддерживаете его между вызовами метода WCF, например. имея его как статическую переменную в вашем бэкэнд и используя ее в объявлении.

Это должно работать, чтобы применить ленивую загрузку к вашему контексту БД для EF 6 и новее, хотя он работает аналогично для более старых версий. (Я реализовал унаследованный класс, чтобы помочь справиться с конфигурациями. Это может не потребоваться)

public class DomainDbContext : DbContext
{
    Configuration.LazyLoadingEnabled = false;
}

Ответ 2

Создавая свои свойства Virtual, вы делаете ленивую загрузку.

Вместо этого вы можете создавать свойства в ICollection и вместо этого загружать загрузку.