2015-05-20 2 views
15

Я наткнулся на странную ошибку в моем коде. Это работало раньше, но теперь работает иногда.Прикрепление объекта типа «X» не удалось, поскольку другой объект того же типа

Я использую EF6 для редактирования объекта с некоторыми отношениями. Чтобы не изменять отношения, я их прикрепляю (см. Пример кода).

public void EditA(A ThisIsA, B ThisIsB) 
    { 
     using (var Context = new LDZ_DEVEntities()) 
     { 
      Context.As.Attach(ThisIsA); 

      var b = Context.Bs.FirstOrDefault(x => x.BId == ThisIsB.BId); 
      //var b = Context.Bs.Find(ThisIsB.BId); 

      if (b != null) 
       Context.Bs.Attach(b); 
      else 
       b = ThisIsB; 

      if (b.C != null) 
       Context.Cs.Attach(b.C); 

      ThisIsA.Bs.Add(b); 

      Context.SaveChanges(); 

     } 
    } 

Я отредактировал названия, чтобы это было просто.

Следующая строка

Context.Cs.Attach(b.C); 

выдает эту ошибку:

Attaching an entity of type 'C' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.

Эта линия была введена потому, что все объекты C статические объекты. Я никогда не хочу, чтобы C был создан. Если я удалю эту строку, каждый раз, когда я добавлю B в A; создается C. Что нежелательно.

Дополнительно:
А имеет список Б
B имеет один C

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

Я прочитал эти вопросы плюс ответы, но они не работали для меня:

  1. ASP.NET MVC - Attaching an entity of type 'MODELNAME' failed because another entity of the same type already has the same primary key value

  2. Attaching an entity of type failed because another entity of the same type already has the same primary key value

+1

Если А имеет список B и B имеет один C, вам нужно всего лишь приложить А. Bs и Cs будет автоматически вставлен ... –

+0

C являются статическими объектами. Я никогда не хочу вставлять их. B нужно только вставить, если B еще не существует. –

+0

Что вы подразумеваете под «статическими сущностями»? В соответствии с вашим кодом есть набор данных объектов C. Как они могут быть «статическими»? – Kryptos

ответ

18

Я установил его.

В Фабио Луз его ответ, он сказал:

//if A has been loaded from context
//dont attach it
//if it has been created outside of the context
//Context.Entry(ThisIsA).State = EntityState.Modified;

Это заставило меня думать, поэтому я отредактировал мой код для этого:

public void EditA(A ThisIsA, B ThisIsB) 
{ 
    using (var Context = new LDZ_DEVEntities()) 
    { 
     var a = Context.As.Find(ThisIsA.AId); 

     //var b = Context.Bs.FirstOrDefault(x => x.BId == ThisIsB.BId); 
     var b = Context.Bs.Find(ThisIsB.BId); 

     if (b != null) 
      Context.Bs.Attach(b); 
     else 
      b = ThisIsB; 

     if (b.C != null) 
      Context.Cs.Attach(b.C); 

     a.Bs.Add(b); 

     Context.SaveChanges(); 

    } 
} 

Сводка изменений:

  • Изменено FirstOrDefault, чтобы найти
  • Получить A из Cont ext

Сначала я удалил Attach of C, в результате это создало новый объект. Итак, я изменил это изменение.

Особая благодарность Фабио Лусу. Я не мог бы сделать это без твоей помощи!

+1

Добро пожаловать, друг! Спасибо за комплименты. Отметьте свой пост как ответ, чтобы помочь другим в будущем. : D –

+0

Это действительно помогло мне - я загружал объект, который редактировал в отдельной переменной, и не думал, что трекер изменений будет отслеживать другую версию и сравнивать их. Как только я удалю другую ссылку, переход на EntityState.Modified работал как шарм. Благодарю. – keithl8041

+0

Нет проблем keithl8041, помогите проголосовать за это сообщение полезно, чтобы мы могли помочь людям найти ответ, который может им помочь –

5

Взгляните на следующую ссылку https://msdn.microsoft.com/en-us/data/jj592676.aspx

Если вы иметь сущность, которая, как вы знаете, уже существует в базе данных, но какие изменения могут быть сделаны, вы можете сказать, что контекст должен привязать объект и установить его состояние в Модифицированное. Например:

var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" }; 

using (var context = new BloggingContext()) 
{ 
    context.Entry(existingBlog).State = EntityState.Modified; 

    // Do some more work... 

    context.SaveChanges(); 
} 

Примечание: вы не должны делать это со всеми объектами (A, B и C), только с А.

EDIT 1

Основываясь на вашем комментарий, попробуйте следующее:

//check if 
var _b = Context.Bs.Find(ThisIsB.BId); 

if (_b != null) 
    //b doesn't exist, then add to the context 
    //make sure that the primary key of A is set. 
    //_b.PrimaryKeyOfA = someValue; 
    Context.Bs.Add(_b); 
else 
//b already exists, then modify the properties 
//make sure that the primary key of A is set. 

Context.SaveChanges(); 

EDIT 2

Я не тестировал, но он должен работать.

+0

К сожалению, это не устранило проблему. Этот метод используется для добавления B в A .. Поэтому я хочу только зарегистрировать изменение в отношении между A и B .. и если B не существует .. B будет создан (что происходит в A.Bs.Add (В)). –

+0

Посмотрите на ** Редактировать 1 ** –

+0

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

2

Другой способ, в зависимости от вашей ситуации, состоит в том, чтобы просто отсоединить государство сущности.

[HttpPost] 
[ValidateAntiForgeryToken] 
public ActionResult Modify(Model model) 
{ 

if (model.Image == null) 
{ 
Model item = db.Model.Find(model.Name); 

// Get the Content needed: 
model.Image = item.Image; 

// Detach the Comparison State: 
db.Entry(item).State = EntityState.Detached; 
} 

if (ModelState.IsValid) 
{ 
db.Entry(model).State = EntityState.Modified; 
db.SaveChanges(); 
return RedirectToAction("Index"); 
} 

return View(model); 
} 

Делая это: db.Entry(item).State = EntityState.Detached; государство в EntityFramework цела, и вы можете сохранить изменения в базу данных (БД).

Надеюсь, это поможет!

-1

присоединить или установить объект, чтобы модифицировать не работать на моем случае, но эта работа для меня:

public int GuardarAsociacionesBonos(List<O_Bono_ConfiguracionPago> bonos) 
{ 
    if (!bonos.Any()) return bonos.Count; 

    using (var contexto = new TouchERPEntities()) 
    { 
     foreach (var bono in bonos) 
     { 
      var existe = contexto.O_Bono_ConfiguracionPago.SingleOrDefault(x => x.IDBono == bono.IDBono && x.IDConfiguracionPago == bono.IDConfiguracionPago); 
      if (existe != null && existe.IDBonoConfigPago != 0) 
      { 
       bono.IDBonoConfigPago = existe.IDBonoConfigPago; 
       contexto.Entry(existe).CurrentValues.SetValues(bono); 
      } 
      else 
      { 
       contexto.O_Bono_ConfiguracionPago.Add(bono); 
      } 

     } 

     contexto.SaveChanges(); 

    } 

    return bonos.Count; 
} 
Смежные вопросы

 Смежные вопросы