我正在尝试使用EF代码优先删除数据库记录(deleteMe
)及其子项(deleteMe.Prices
)。
foreach (var deleteMe in deleteThese)
{
// Delete validation
if(CanDeleteItem(deleteMe.ItemId))
{
db.Entry(deleteMe).State = EntityState.Deleted;
foreach (var item in deleteMe.Prices)
{
db.Entry(item).State = EntityState.Deleted; // cascade delete
}
}
}
db.SaveChanges();
但是,Entity Framework似乎无法跟踪在父级之前应删除子级记录的事实。我收到错误:
DELETE语句与REFERENCE约束“ItemPrice_Item”冲突 冲突发生在数据库“DEVDB”,表“dbo.ItemPrices”中, 列'Item_ItemId'。
声明已经终止。
我如何在EF中执行此删除?
答案 0 :(得分:34)
我最终找到了一条为我做的快速行:
foreach (var deleteMe in deleteThese)
{
// Delete validation
if(CanDeleteItem(deleteMe.ItemId))
{
///
deleteMe.Prices.ToList().ForEach(p => db.ItemPrices.Remove(p));
///
db.Entry(deleteMe).State = EntityState.Deleted;
}
}
db.SaveChanges();
答案 1 :(得分:10)
EF6
context.Children.RemoveRange(parent.Children)
答案 2 :(得分:8)
EF中的级联删除取决于数据库中关联配置的级联删除,因此如果您没有在数据库中配置级联删除,则必须先将所有项目价格加载到应用程序并将其标记为已删除。
答案 3 :(得分:5)
最简单的解决方案是首先迭代价格并调用保存更改,然后将条目设置为deleteMe删除并再次调用保存更改,但是你检查过这个:Entity framework code first delete with cascade?这似乎是你想要的。
很奇怪,为什么你不是要删除上下文中的实体来删除而是设置条目状态?
另一种选择是设置级联删除http://blogs.msdn.com/b/alexj/archive/2009/08/19/tip-33-how-cascade-delete-really-works-in-ef.aspx
做这样的事情(没有经过测试,但希望你能得到这个):
using (TransactionScope scope = new TransactionScope())
{
foreach (var deleteMe in deleteThese)
{
// Delete validation
if(CanDeleteItem(deleteMe.ItemId))
{
foreach (var item in deleteMe.Prices)
{
db.Entry(item).State = EntityState.Deleted; // cascade delete
}
db.SaveChanges();
db.Entry(deleteMe).State = EntityState.Deleted;
}
}
db.SaveChanges();
scope.Complete();
}
另外你可以打电话:
db.Prices.Remove(item);
和
db.DeleteMes.Remove(deleteMe);
而不是设置条目状态。不确定两者之间的幕后是否存在差异。
答案 4 :(得分:3)
实体框架中的级联删除是件棘手的事情,因为你需要确定删除实体对象图。最好总是为这些级联删除编写集成测试。
如果您尝试删除EF中的父实体,它将尝试为当前dbcontext中的任何子实体执行delete语句。因此,它不会初始化任何尚未加载的子实体。这将导致RDBMS运行时错误,这违反了外键约束。为了安全起见,请确保在删除之前将所有依赖实体加载到当前dbcontext。
答案 5 :(得分:0)
如果您的对象是自引用的,则可以使用以下方法删除多对多和一对多的子对象。记得以后调用db.SaveChanges():)
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
Object obj = this.db.Objects.Find(id);
this.DeleteObjectAndChildren(obj);
this.db.Objects.Remove(obj);
this.db.SaveChanges();
return this.Json(new { success = true });
}
/// <summary>
/// This deletes an object and all children, but does not commit changes to the db.
/// - MH @ 2016/08/15 14:42
/// </summary>
/// <param name="parent">
/// The object.
/// </param>
private void DeleteObjectAndChildren(Object parent)
{
// Deletes One-to-Many Children
if (parent.Things != null && parent.Things.Count > 0)
{
this.db.Things.RemoveRange(parent.Things);
}
// Deletes Self Referenced Children
if (parent.Children != null && parent.Children.Count > 0)
{
foreach (var child in parent.Children)
{
this.DeleteObjectAndChildren(child);
}
this.db.Objects.RemoveRange(parent.Children);
}
}
答案 6 :(得分:0)
我有一个类似的问题,对我来说,我好像没有正确建立父母和孩子在各自班级之间的关系。
我的解决方法是将以下指定的属性添加到Child类中,以表示代表其父级ID的属性
public class Child
{
[Key, Column(Order = 1)]
public string Id { get; set; }
[Key, ForeignKey("Parent"), Column(Order = 2)] // adding this line fixed things for me
public string ParentId {get; set;}
}
public class Parent
{
[Key, Column(Order = 1)]
public string Id { get; set; }
...
public virtual ICollection<Child> Children{ get; set; }
}
答案 7 :(得分:0)
以下内容非常有效。 为数据库中的每个关系表添加以下内容(在上下文文件中)。
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder
.Entity<TableA>()
.HasMany(x => x.TableB)
.WithRequired(x => x.TableA)
.WillCascadeOnDelete();
modelBuilder
.Entity<TableC>()
.HasMany(x => x.TableD)
.WithRequired(x => x.TableC)
.WillCascadeOnDelete();
modelBuilder
.Entity<TableE>()
.HasMany(x => x.TableF)
.WithRequired(x => x.TableE)
.WillCascadeOnDelete(); }
然后在您的代码中,不要忘记删除之前加载这些表
context.TableA.Load();
context.TableB.Load();
context.TableC.Load();
context.TableD.Load();
context.TableE.Load();
context.TableF.Load();
var tableAEntity= TableA.Where(x => x.Condition == [yourcondition].FirstOrDefault();
context.TableA.Remove(tableAEntity);
context.SaveChanges();
这将非常快速有效地从主条目表和所有连接的表记录(通过FK相关联)中删除实体(记录)(即使关系在多个层次上深层级联)。
答案 8 :(得分:0)
_context.Remove(parent);
_context.RemoveRange(_context.Childrens
.Where(p => parent.Childrens
.Select(c => c.Id).Contains(p.Id)));