1

Каждый раз, когда я хочу обновляемой мои записи, я получаю следующее сообщение об ошибке:EntityFramework 7 Ошибка при обновлении рекорд

"The instance of entity type 'User' cannot be tracked because another instance of this type with the same key is already being tracked. When adding new entities, for most key types a unique temporary key value will be created if no key is set (i.e. if the key property is assigned the default value for its type). If you are explicitly setting key values for new entities, ensure they do not collide with existing entities or temporary values generated for other new entities. When attaching existing entities, ensure that only one entity instance with a given key value is attached to the context."

Вот мой код:

public void SaveRecipient(Recipient myRecipient) 
{ 
    if (myRecipient.RecipientGUID == Guid.Empty) 
    { 
     myRecipient.RecipientGUID = Guid.NewGuid(); 

     foreach (ContactMethod tmpCM in myRecipient.ContactMethods) 
     { 
      context.Entry(tmpCM.Type).State = EntityState.Unchanged; 
     } 

     context.Entry(myRecipient.LastModifiedBy).State = EntityState.Unchanged; 
     context.Entry(myRecipient.Owner).State = EntityState.Unchanged; 
     context.Entry(myRecipient.CreatedBy).State = EntityState.Unchanged; 

     context.Recipients.Add(myRecipient); 
    } 
    else 
    { 
     var dbRecipient = context.Recipients 
      .Include(a => a.ContactMethods).ThenInclude(t => t.Type) 
      .Include(b => b.CreatedBy) 
      .Include(c => c.LastModifiedBy) 
      .Include(d => d.Owner).ThenInclude(o => o.Users) 
      .FirstOrDefault(x => x.RecipientGUID == myRecipient.RecipientGUID); 

     if (dbRecipient != null) 
     { 
      dbRecipient.FirstName = myRecipient.FirstName; 
      dbRecipient.LastName = myRecipient.LastName; 
      dbRecipient.Company = myRecipient.Company; 

      foreach (ContactMethod tmpCM in myRecipient.ContactMethods) 
      { 
       var dbCM = dbRecipient.ContactMethods.FirstOrDefault(x => x.ContactMethodGUID == tmpCM.ContactMethodGUID); 

       if (dbCM != null) 
       { 
        dbCM.CountryCode = tmpCM.CountryCode; 
        dbCM.Identifier = tmpCM.Identifier; 
        dbCM.IsPreferred = tmpCM.IsPreferred; 
       } 
       else 
       { 
        dbRecipient.ContactMethods.Add(tmpCM); 
       } 
      } 

      //Only update this if it has changed. 
      if (dbRecipient.LastModifiedBy.UserGUID != myRecipient.LastModifiedBy.UserGUID) 
      { 
       dbRecipient.LastModifiedBy = myRecipient.LastModifiedBy; 
      } 

      dbRecipient.LastModifiedOn = myRecipient.LastModifiedOn; 
     } 
    } 

    context.SaveChanges(); 
} 

Соответствующие классы:

Пользователь:

public class User 
    { 
     [Key] 
     public Guid UserGUID { get; set; } 

     public string UserName { get; set; } 

     public string FirstName { get; set; } 

     public string LastName { get; set; } 

     public string Email { get; set; } 

     public bool IsSiteAdmin { get; set; } 

     public bool IsActive { get; set; } 

     public DateTime? CreatedOn { get; set; } 

     public DateTime? LastLogin { get; set; } 
    } 

Получатель:

public class Recipient 
    { 
     [Key] 
     public Guid RecipientGUID { get; set; } 

     [Required(ErrorMessage = "Please enter a Recipient's First Name.")] 
     public string FirstName { get; set; } 

     [Required(ErrorMessage = "Please enter a Recipient's Last Name.")] 
     public string LastName { get; set; } 

     public string Company { get; set; } 

     public UserGroup Owner { get; set; } 

     public virtual ICollection<ContactMethod> ContactMethods { get; set; } 

     public User CreatedBy { get; set; } 

     public DateTime CreatedOn { get; set; } 

     public User LastModifiedBy { get; set; } 

     public DateTime LastModifiedOn { get; set; } 

     public bool IsActive { get; set; } 
    } 

Контакт Метода:

public class ContactMethod 
    { 
     [Key] 
     [HiddenInput(DisplayValue = false)] 
     public Guid ContactMethodGUID { get; set; } 

     [ForeignKey("ContactMethodTypeGUID")] 
     public virtual ContactMethodType Type { get; set; } 

     public string CountryCode { get; set; } 

     [Required] 
     public string Identifier { get; set; } 

     public bool IsPreferred { get; set; } 

     [ForeignKey("RecipientGUID")] 
     public virtual Recipient Owner { get; set; } 
    } 

Эта проблема возникает, когда я хочу, чтобы обновить получатель, и это еще один пользователь делает обновление. Поэтому скажите, что пользователь abcd сделал последнее обновление, но теперь пользователь zyx обновляет запись. Таким образом, Recipeint.LastUpdatedBy установлен на текущего пользователя сеанса. Когда я это сделаю, я получаю вышеуказанную ошибку. Я не могу понять, как выйти за рамки этого.

Небольшое примечание: если я добавлю это:

context.Entry(myRecipient.LastModifiedBy).State = EntityState.Unchanged; 

в заявлении if (dbRecipient.LastModifiedBy.UserGUID != myRecipient.LastModifiedBy.UserGUID)

, и говорят, пользователь lastmodifiedby устанавливается на пользователя аЬс. Теперь пользователь asfg впервые обновляет этого получателя, он проходит, и LastModifiedBy будет настроен на пользователя asfg, но скажите, что пользователь abc вернулся и снова изменил получателя, поэтому lastmodifiedby возвращается к abc, он терпит неудачу, с той же ошибкой ,

Это сводит меня с ума, и я не могу понять это!

+0

Вы используете Dependency Injection? Может быть, вы использовали класс, который 'SaveRecipient' определен в качестве Singleton? Он должен быть «Scoped», так что у вас есть контекст для запроса. –

+0

Да, я. Спасибо, я посмотрю. – MarekT

+0

Итак, мой класс получателей содержит два поля пользователя. Один для CreatedBy, а другой для LastModifiedBy. Поэтому, когда они настроены на одного пользователя, я получаю эту ошибку. Я не думаю, что с моей моделью что-то не так, я имею в виду, что имеет смысл организовать ее таким образом. – MarekT

ответ

1

Я получил ответ на этот вопрос от Arthur Vickers от Microsoft. Я хотел поделиться.

Код, устанавливающий свойство навигации dbRecipient.LastModifiedBy, устанавливает его в экземпляр объекта, который не отслеживается контекстом. Похоже, что в этом случае контекст уже отслеживает другой экземпляр для этого же объекта - предположительно потому, что он был внесен в запрос путем включения навигации CreatedBy.
EF не может отслеживать два экземпляра одного и того же объекта, поэтому исключение выбрасывается, поэтому вам нужно предоставить дополнительную информацию EF здесь, чтобы знать, что делать. Это может быть сложным в общем случае.
Например: если отслеживаемый экземпляр имеет свойства, которые были изменены в другом экземпляре.
Однако, если предположить, что это не так, то вы можете просто LookUp экземпляр, который будет отслеживаться, и использовать его вместо того, чтобы, например:

if (dbRecipient.LastModifiedBy.UserGUID != myRecipient.LastModifiedBy.UserGUID) 
{ 
    dbRecipient.LastModifiedBy = test.Set<User>().Find(myRecipient.LastModifiedBy.UserGUID); 
}