2014-11-12 1 views
7

Сообщение об ошибке: Прикрепление объекта типа не удалось, поскольку другой объект того же типа уже имеет такое же значение первичного ключа.Прикрепление объекта типа не удалось, поскольку другой объект того же типа уже имеет такое же значение первичного ключа

Вопрос: Как связать объект таким же образом, как показано в методе AttachActivity в коде ниже?

Я должен предположить, что часть сообщения об ошибке «другая сущность» выше относится к объекту, который существует в памяти, но выходит за рамки (??). Я отмечаю это потому, что локальное свойство DBSet для типа сущности, которое я пытаюсь прикрепить, возвращает ноль.

Я уверен, что сущности не существуют в контексте, потому что я просматриваю код и наблюдаю за контекстом по мере его создания. Объекты добавляются в несколько строк сразу после создания dbcontext.

тестирования Am для прикрепленных лиц, как указано здесь: what is the most reasonable way to find out if entity is attached to dbContext or not?

Глядя на местных жителях в окне местных жителей визуальной студии я не вижу сущности типа деятельности (независимо от ID), за исключением того, что я пытаюсь прикрепить.

Код выполняется в следующем порядке: Try -> ModifyProject -> AttachActivity

код не в AttachActivity на комментировал линии.

Обратите внимание на код между отладочными комментариями, которые будут выдаваться, если какие-либо объекты были добавлены в контекст.

private string AttachActivity(Activity activity) 
    { 
     string errorMsg = ValidateActivity(activity); // has no code yet. No. It does not query db. 

     if(String.IsNullOrEmpty(errorMsg)) 
     { 
      // debug 
      var state = db.Entry(activity).State; // Detached 
      int activityCount = db.Activities.Local.Count; 
      int projectCount = db.Activities.Local.Count; 

      if (activityCount > 0 || projectCount > 0) 
       throw new Exception("objects exist in dbcontext"); 
      // end debug 
      if (activity.ID == 0) 
       db.Activities.Add(activity); 
      else 
      { 
       db.Activities.Attach(activity); // throws here 
       db.Entry(activity).State = System.Data.Entity.EntityState.Modified; 
      } 
     } 
     return errorMsg; 
    } 


public int ModifyProject(Presentation.PresProject presProject, out int id, out string errorMsg) 
    { 
     // snip 

     foreach (PresActivity presActivity in presProject.Activities) 
     { 
      Activity a = presActivity.ToActivity(); // returns new Activity object 
      errorMsg = ValidateActivity(a);   // has no code yet. No. It does not query db. 
      if (String.IsNullOrEmpty(errorMsg)) 
      { 
       a.Project = project; 
       project.Activities.Add(a); 
       AttachActivity(a); 
      } 
      else 
       break; 
     } 
     if (string.IsNullOrEmpty(errorMsg)) 
     { 
      if (project.ID == 0) 
       db.Projects.Add(project); 
      else 
       db.AttachAsModfied(project); 
      saveCount = db.SaveChanges(); 
      id = project.ID; 
     } 
     return saveCount; 
    } 

Это класс, новости вверх по DbContext:

public void Try(Action<IServices> work) 
    { 
     using(IServices client = GetClient()) // dbContext is newd up here 
     { 
      try 
      { 
       work(client); // ModifyProject is called here 
       HangUp(client, false); 
      } 
      catch (CommunicationException e) 
      { 
       HangUp(client, true); 
      } 
      catch (TimeoutException e) 
      { 
       HangUp(client, true); 
      } 
      catch (Exception e) 
      { 
       HangUp(client, true); 
       throw; 
      } 
     } 

Я не спрашиваю: Как использовать AsNoTracking What difference does .AsNoTracking() make?

+0

Почему Entity Framework повторно вставляет существующие объекты в мою базу данных? msdn.microsoft.com/en-us/magazine/dn166926.aspx – Colin

+0

@Colin - хороший улов - и я подумал об этом. В моем проекте класс Project имеет свойство, которое является списком . Однако в коде отладки в AddActivity я проверяю любые объекты проекта, добавленные в контекст, и их нет. – Sam

+0

Пожалуйста, посмотрите мой ответ на [ASP.NET MVC. Прикрепление объекта типа «MODELNAME» не выполнено, потому что другой объект того же типа уже имеет такое же значение первичного ключа] (http://stackoverflow.com/questions/ 23201907/жерех-сетчатой ​​MVC-прикрепление-ан-объект-в-типа-ModelName-не удалось, потому-другой-лор/39557606 # 39557606). –

ответ

19

Одно решение, чтобы избежать получения этой ошибки используется Find метод , перед присоединением объекта запрос DbContext для желаемого объекта, если сущность существует в памяти, вы получаете локальный объект, иначе объект будет извлекаться из базы данных.

private void AttachActivity(Activity activity) 
{ 
    var activityInDb = db.Activities.Find(activity.Id); 

    // Activity does not exist in database and it's new one 
    if(activityInDb == null) 
    { 
     db.Activities.Add(activity); 
     return; 
    } 

    // Activity already exist in database and modify it 
    db.Entry(activityInDb).CurrentValues.SetValues(activity); 
    db.Entry(activityInDb).State = EntityState.Modified; 
} 
+0

Я присоединяю объект с состоянием Модифицированный, который должен сгенерировать инструкцию обновления для db. Я случайно нажал кнопку «downvote», чтобы продолжить ее отмену. Ответ показывает, что один взнос должен быть равен нулю. – Sam

+0

@Mohsen: Ваш ответ решил мою проблему со второго раза. Благодарю. –

3

Я решил эту ошибку, изменив метод обновления, как показано ниже.

, если вы используете общий репозиторий и Entity

_dbContext.Set<T>().AddOrUpdate(entityToBeUpdatedWithId); 

или нормальный (не общий) хранилище и объект, а затем

_dbContext.Set<TaskEntity>().AddOrUpdate(entityToBeUpdatedWithId); 

Если вы используете AddOrUpdate() метод, пожалуйста, убедитесь, что вы добавили "System.Data.Entity.Migrations" пространство имен.

4

Прикрепление объекта типа не удалось, поскольку другой объект того же типа уже имеет такое же значение первичного ключа. Это может произойти при использовании метода Attach или установки состояния объекта на Unchanged или Modified, если любые объекты на графике имеют конфликтующие значения ключа. Это может быть связано с тем, что некоторые объекты являются новыми и еще не получили значения ключей базы данных.В этом случае используйте Add.

Решение состоит в том, что

, если вы должны были использовать GETALL()

public virtual IEnumerable<T> GetAll() 
{ 
    return dbSet.ToList(); 
} 

Изменение Для

public virtual IEnumerable<T> GetAll() 
{ 
    return dbSet.AsNoTracking().ToList(); 
}