2015-04-28 2 views
0

Я хочу обновить только простые свойства объекта MwbePaymentMethod, без сложных свойств (4 последних свойства являются сложными), поэтому он изменяет эти 4 комплексных свойства на неизмененные. Но метод Edit терпит неудачу в строке:Обновление сложного объекта в контексте БД

Context.Entry(payment.BillingAddress).State = EntityState.Unchanged; 

с ошибкой:

Прикрепление объект типа «MobileWallet.Common.Repository.MwbeAddress» не удалось, так как другой объект того же типа, уже имеет один и тот же значение первичного ключа , Это может произойти при использовании метода «Прикрепить» или установки состояния объекта в «Без изменений» или «Модифицировано», если любые объекты на графике имеют конфликтующие значения ключей. Это может быть связано с тем, что некоторые объекты являются новыми и еще не получили значения ключей базы данных. В этом случае используйте метод «Добавить» или «Добавленное» состояние объекта для отслеживания графика, а затем, если необходимо, установите состояние не новых объектов «Без изменений» или «Модифицировано».

Модель объекта:

public class MwbePaymentMethod : BaseEntity 
    { 
     public enum MethodTypeEnum 
     { 
      Creditcard, 
      Virtualcard, 
      Wallet 
     }; 
     public MethodTypeEnum MethodType { get; set; } 
     public string Number { get; set; } 
     public DateTime? ExpirationDate { get; set; } 
     public double Balance { get; set; } 
     public bool IsPending { get; set; } 
     public bool IsDefault { get; set; } 
     public MwbeAddress BillingAddress { get; set; } 
     public MwbeCurrency Currency { get; set; } 
     public MwbeUserData UserData { get; set; } 
     public DateTime? PaymentDate { get; set; } 

     [JsonIgnore] 
     public virtual ICollection<MwbePayment> Payments { get; set; } 
    } 

Изменить метод:

public override void Edit(MwbePaymentMethod payment) 
     { 

      if (payment.Currency != null && payment.Currency.Id != 0) 
      { 
       Context.Entry(payment.Currency).State = EntityState.Unchanged; 
      } 
      if (payment.UserData != null && payment.UserData.Id != 0) 
      { 
       Context.Entry(payment.UserData).State = EntityState.Unchanged; 
      } 

      if (payment.BillingAddress != null && payment.BillingAddress.Id != 0) 
      { 
       Debugger.Break(); 
       Context.Entry(payment.BillingAddress).State = EntityState.Unchanged; 
      } 

      Context.Entry(payment).State = EntityState.Modified; 
      if (Context.Entry(payment).State == EntityState.Detached) 
      { 
       DbSet.Attach(payment); 
      } 
     } 

ADDED1:

Я изменил код немного, Im чтение всех навигационных полей/объект особенно Платежный адрес, который не был полностью заполненными теми же данными, что и в базе данных.

public void UpdateMwbePaymentMethod(MwbePaymentMethodFilter filter, MwbePaymentMethodDtoInOut mwbepaymentmethod) 
     { 
      var currentPaymentMethod = paymentMethodRepository.FindBy(x => x.UserData.Id == filter.userId && x.Id == filter.id); 
      if (currentPaymentMethod == null || currentPaymentMethod.Count() != 1) 
      { 
       throw new DBConcurrencyException(); 
      } 
      var mwbePaymentPethod = Mapper.Map<MwbePaymentMethod>(mwbepaymentmethod); 

      //load existing user data 
      mwbePaymentPethod.UserData = userRepository.Get(filter.userId).Data; 

      //load existing address with subproperties 
      mwbePaymentPethod.BillingAddress = addressRepository.FindBy(x => x.Id == mwbePaymentPethod.BillingAddress.Id, x=>x.Merchants, x=>x.PaymentMethods, x=>x.Deliveries, x=>x.UserDatas).SingleOrDefault(); 

      if (mwbePaymentPethod.BillingAddress == null) 
      { 
       throw new DBConcurrencyException(); 
      } 

      paymentMethodRepository.Edit(mwbePaymentPethod); 
      paymentMethodRepository.SaveChanges(); 
     } 

И Изменить метод:

public override void Edit(MwbePaymentMethod payment) 
    { 

     if (payment.Currency != null && payment.Currency.Id != 0) 
     { 
      Context.Entry(payment.Currency).State = EntityState.Unchanged; 
     } 
     if (payment.UserData != null && payment.UserData.Id != 0) 
     { 
      Context.Entry(payment.UserData).State = EntityState.Unchanged; 
     } 

     if (payment.BillingAddress != null && payment.BillingAddress.Id != 0) 
     { 
      Debugger.Break(); // tutaj byl ostatnio problem 
      Context.Entry(payment.BillingAddress).State = EntityState.Unchanged; 
     } 
     Context.Entry(payment).State = EntityState.Modified; 

    } 

Независимо от того, если

1) Context.Entry(payment.BillingAddress).State = EntityState.Unchanged;

или

2) Context.Entry(payment.BillingAddress).State = EntityState.Modified;

Отображается та же ошибка. Для меня точка 2) должна работать, если я не привязал все свойства из db, но он не работает.

+0

Я ответил, почему у вас возникают проблемы при попытке изменить состояние сложных типов. Я только что заметил еще одну проблему с вашим кодом. Когда вы делаете это 'Context.Entry (платеж) .State = EntityState.Modified;' вы фактически делаете строку ниже 'if (Context.Entry (платеж) .State == EntityState.Detached)' всегда быть false. Сущность не может находиться в двух состояниях одновременно (вы тестируете одно и то же свойство, которое вы только что изменили). – Rui

+0

См. [«Если вопросы включают« теги »в их названиях?») (Http://meta.stackexchange.com/questions/19190/should-questions-include-tags-in-their-titles), где консенсус «нет, они не должны»! –

ответ

0

Сложные типы не являются сущностями, поэтому они не отслеживаются. Суть, к которой они принадлежат, есть.

Чтобы понять, почему это имеет смысл думать об этом так: Ваш MwbePaymentMethod имеет адрес, который является сложным типом. В базе данных они будут храниться в одной таблице, (по умолчанию) имена столбцов: Количество, MwbeAddress_Line1, MwbeAddress_Line2, MwbeAddress_PostalCode ...

При изменении line1 адреса, строки на целый MwbePaymentMethod таблицы в необходимо обновить базу данных. Фактически, если вы измените любое значение любого сложного свойства, которое принадлежит объекту MwbePaymentMethod, что приведет к обновлению всей сущности (потому что в конце концов все они принадлежат к одной и той же таблице в БД).

Вот почему не имеет смысла «обновлять только простые свойства объекта MwbePaymentMethod, без [обновления] сложных свойств».

Вы можете изменить состояние (Context.Entry (Entity) .State = ...) объектов в DbSets в вашем контексте (т.все X в DbSet в вашем классе Context)

См. this. В частности, раздел с именем: Сложные типы: Разделение таблицы по нескольким типам

0

В первой строке редактирования коды прикрепить объект к контексту:

DbSet.Attach(payment); 

Примечание:DbSet не имеет статический Attach способ. Это должно быть свойство DbSet<MwbePaymentMethod >, определенное в вашем контексте.

После того, как вы сделали это, установите состояние платежа изменения:

Context.Entry(payment).State = EntityState.Modified; 

Затем установите состояние всех других субъектов. Учтите, что когда вы привязываете дерево к контексту, оно привязывается в неизмененном состоянии. Из MSDN Attach документы:

Attach is used to repopulate a context with an entity that is known to already exist in the database. SaveChanges will therefore not attempt to insert an attached entity into the database because it is assumed to already be there. Note that entities that are already in the context in some other state will have their state set to Unchanged. Attach is a no-op if the entity is already in the context in the Unchanged state.

Таким образом, вы должны прикрепить к контексту, а затем изменить состояние на smething еще, как добавил, когда это необходимо. Вы делаете наоборот.

И, наконец, убедитесь, что объект payment имеет правильный идентификатор. Если его там нет, вы должны включить его в скрытое поле или любой другой ввод формы, чтобы он был отправлен обратно на сервер.

+0

Спасибо за ответ :): 1) В реальном im с использованием внутреннего DbSet DbSet, поэтому набор DB строго типизирован. 2) Я не знаю, Im добавляет объект, который был изменен, но ошибка в том, что под-объект MwbeAddress уже находится в системе. Но я не изменил его и просто хочу изменить его на Unchanged .... чтобы не обмануть этот объект в DB .... Я не понимаю вашего объяснения –