Entity Framework - очистка детской коллекции
У меня возникла интересная проблема с Entity Framework и на основе кода, который я должен был использовать для решения этой проблемы, я подозреваю, что мое решение менее чем идеально. У меня есть соотношение 1-ко-многим между таблицей A и таблицей B, где объекты в TableB имеют ссылку на TableA. У меня есть сценарий, когда я хочу одновременно удалить всех дочерних элементов в таблице A, и я думал, что этого можно добиться, просто очистив коллекцию:
Entity.Children.Clear()
К сожалению, когда я попытался сохранить изменения, это было вызвано нарушением внешнего ключа.
Добавляется отношение или удалено из набора AssociationSet 'FK_EntityB_EntityA. С мощностью ограничений, соответствующий "EntityB" также должны быть добавлены или удалены.
Решение, с которым я столкнулся, состояло в том, чтобы вручную удалить объект через контекст сущности DeleteObject(), но я просто знаю, что эта логика, которую я использую, должна быть неправильной.
while (collection.Any())
Entities.DeleteObject(collection.First());
Во-первых, тот факт, что мне пришлось использовать цикл Where(), кажется гораздо менее идеальным, но я полагаю, что чисто семантическая оценка с моей стороны. В любом случае, что-то не так с тем, как я это делаю, или может быть лучший способ очистить коллекцию дочерних сущностей сущности, чтобы Entity Framework правильно вызывала удаление хранилища данных на всех удаленных объектах?
Ответы
Ответ 1
Clear()
удаляет ссылку на объект, а не на сам объект.
Если вы намереваетесь, чтобы это была всегда одна и та же операция, вы могли бы обрабатывать AssociationChanged
:
Entity.Children.AssociationChanged +=
new CollectionChangeEventHandler(EntityChildrenChanged);
Entity.Children.Clear();
private void EntityChildrenChanged(object sender,
CollectionChangeEventArgs e)
{
// Check for a related reference being removed.
if (e.Action == CollectionChangeAction.Remove)
{
Context.DeleteObject(e.Element);
}
}
Вы можете построить это для своей сущности, используя неполный класс.
Ответ 2
Вы можете создать идентификацию отношений между родительскими и дочерними объектами, а EF удалит дочерний объект, когда вы удалите его из родительской коллекции.
public class Parent
{
public int ParentId {get;set;}
public ICollection<Child> Children {get;set;}
}
public class Child
{
public int ChildId {get;set;}
public int ParentId {get;set;}
}
Конфигурация отображения:
modelBuilder.Entity<Child>().HasKey(x => new { x.ChildId, x.ParentId });
modelBuilder.Entity<Parent>().HasMany(x => x.Children).WithRequired().HasForeignKey(x => x.ParentId);
Ответ 3
Трюк: при настройке отношений между родителем и ребенком вы должны создать "составной" ключ для ребенка. Таким образом, когда вы сообщите родительу удалить 1 или все его дочерние элементы, соответствующие записи будут фактически удалены из базы данных.
Чтобы настроить составной ключ с использованием Fluent API:
modelBuilder.Entity<Child>().HasKey(t => new { t.ParentId, t.ChildId });
Затем, чтобы удалить связанные дочерние элементы:
var parent = _context.Parents.SingleOrDefault(p => p.ParentId == parentId);
var childToRemove = parent.Children.First(); // Change the logic
parent.Children.Remove(childToRemove);
// you can delete all children if you want
// parent.Children.Clear();
_context.SaveChanges();
Готово!