У меня была такая же проблема с EF. Вот что я в итоге сделал:
- Вместо того, чтобы делать
story1.Tags.Add(new Tag { Name = ".net", })
самостоятельно, маршрутизируем все Tag
создания с помощью вспомогательного метода, подобного этому: story1.Tags.Add(GetTag(".net"))
.
- Метод
GetTag
проверяет теги в контексте, чтобы увидеть, должен ли он вернуть существующую сущность, как вы. Если это так, он возвращает это.
- Если нет существующего объекта, он проверяет
ObjectStateManager
, чтобы увидеть, есть ли Tag
объекты, добавленные в контекст, но еще не записанные в БД. Если он находит соответствующий Tag
, он возвращает это.
- Если он все еще не нашел
Tag
, он создает новый Tag
, добавляет его в контекст и затем возвращает его.
По сути, это гарантирует, что в вашей программе будет использоваться не более одного экземпляра любого Tag
(будь то уже существующий или только что созданный).
Пример кода, снятого с моего проекта (используется InventoryItem
вместо Tag
, но вы поняли).
Проверка на шаге 3 выполняется следующим образом:
// Second choice: maybe it's not in the database yet, but it's awaiting insertion?
inventoryItem = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added)
.Where(ose => ose.EntitySet == context.InventoryItems.EntitySet)
.Select(ose => ose.Entity)
.Cast<InventoryItem>()
.Where(equalityPredicate.Compile())
.SingleOrDefault();
if (inventoryItem != null) {
return inventoryItem;
}
Если Tag
не найден на шаге 3, вот код для шага 4:
inventoryItem = new InventoryItem();
context.InventoryItems.AddObject(inventoryItem);
return inventoryItem;
Обновление:
Следует использовать так:
Story story1 = new Story();
story1.Title = "Introducing the Entity Framework";
story1.Tags.Add(GetTag(".net", category, db));
story1.Tags.Add(GetTag("database", category, db));