Добавление объекта в entityset создает нежелательную новую строку БД (многие-ко-многим). Создать отношения с существующим объектом? - PullRequest
2 голосов
/ 04 августа 2011

Я - давний читатель - первый постер - и после бесчисленных часов исследований по этой проблеме Entity Framework я почувствовал, что мне нужна помощь.Я новичок в C # и новичок в программировании, поэтому, пожалуйста, потерпите меня.

У меня довольно простое отношение «многие ко многим» в моей модели данных со стилем «2.0» в стиле Web 2.0.У смен есть теги, а у пользователей есть теги.

Я вытаскиваю смену из кэша.Когда я пытаюсь сделать копию смены, копируя сведения о смене и теги из кэшированной копии, я делаю следующее (упрощенно).

Data.Shift s = new Data.Shift();

/* copy over a bunch of stuff from the cached shift object. I'll spare the boring details */    

foreach (var t in shift.Tags) {  //shift object is a cached object

                Data.Tag dt = new Data.Tag
                {
                    TagID = t.TagID,
                    Name = t.Name,
                    OrgID = t.OrgID,
                };
                s.Tags.Add(dt);
            }

Даже если я явно установил TagID вНовый объект Data.Tag, в SaveChanges () новый тег вставляется в БД, а не просто создается связь с тегом, который уже существует в БД.TagID - это столбец идентификатора PK

Когда я пытаюсь использовать следующий код:

foreach (var t in shift.Tags){
   s.Tags.Add(t)
}

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

Есть мысли?Насколько я могу сказать:

  • Очистка кэша для меня не вариант из-за проблем с производительностью - я понимаю, что вся эта проблема исчезнет, ​​если я выполню эту работу в том же контексте объекта,
  • Кроме того, извлечение Data.Tag из БД в текущем контексте не вариант из-за проблем перфорирования.

Это кажется очень простой вещью, которую я пытаюсь сделать...

Редактировать Хорошо - я пытался обновить мой код с обоими решениями, но у меня проблемы с обоими.Давайте попробуем первый:

// ctx is grabbed up here from HttpContext.Current.Items

 Data.Shift s = new Data.Shift();

 /* copy over a bunch of stuff from the cached shift object. I'll spare the boring details */    

foreach (var t in shift.Tags) {  //shift object is a cached object

            Data.Tag dt = new Data.Tag
            {
                TagID = t.TagID,
                Name = t.Name,
                OrgID = t.OrgID,
            };
            ObjectStateEntry entry;
            ctx.ObjectStateManager.TryGetObjectStateEntry(t.EntityKey, out entry);
            if (entry == null || entry.State == EntityState.Detached) { 
                    ctx.Tags.Attach(t);
            }
            s.Tags.Add(dt);
        }

Это выдает следующую ошибку:

  An entity object cannot be referenced by multiple instances of IEntityChangeTracker.

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

1 Ответ

1 голос
/ 04 августа 2011

Неважно, если вы установите TAgId на существующее значение или нет.EF тупой - он не делает Upsert / Merge для вас.Он не проверяет, существует ли такая же сущность, и если TagId автоматически генерируется в базе данных, он даже выбрасывает ваше значение, когда вы вызываете SaveChanges.

Что вы должны сделать?Вы должны вручную указать EF, что Tag не является новой сущностью.

Попробуйте либо:

Data.Shift s = new Data.Shift();
context.Shifts.AddObject(s);  // Add a new shift

foreach (var t in shift.Tags) 
{  //shift object is a cached object
     Data.Tag dt = new Data.Tag
     {
         TagID = t.TagID,
         Name = t.Name,
         OrgID = t.OrgID,
     };
     context.Tags.Attach(Tag); // Attach an existing tag
     s.Tags.Add(dt);
 }
 context.SaveChanges();

, либо

Data.Shift s = new Data.Shift();
foreach (var t in shift.Tags) 
{  //shift object is a cached object
     Data.Tag dt = new Data.Tag
     {
         TagID = t.TagID,
         Name = t.Name,
         OrgID = t.OrgID,
     };
     s.Tags.Add(dt);
 }

 context.Shifts.AddObject(s);
 // Now shift and all tags are added
 // Change the state of each tag to unchanged
 foreach (var tag in s.Tags)
 {
     context.ObjectStateManager.ChangeEntityState(tag, EntityState.Unchanged);
 }
 context.SaveChanges();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...