使用DbContext和Entity Framework 6进行级联删除

时间:2013-12-27 20:51:06

标签: .net entity-framework entity-framework-6

有没有办法在不修改数据库中的外键而不修改edmx的情况下级联删除实体?我有DB,超过100个表使用外键引用删除规则=无操作。

我在“实体框架6食谱”一书中找到了这个漂亮的代码。 但它适用于 ObjectContext ,我需要 DbContext

    private static void DeleteRelatedEntities<T>(T entity, test123Entities1 context)
        where T : EntityObject
    {
        var entities =
            ((IEntityWithRelationships) entity).RelationshipManager.GetAllRelatedEnds()
                .SelectMany(e => e.CreateSourceQuery().OfType<EntityObject>())
                .ToList();

        foreach (var child in entities)
        {
            DeleteRelatedEntities(child, context);
            context.DeleteObject(child);
        }
        context.SaveChanges();
    } 

可以将此方法用于此转换

//var ddd = ((IObjectContextAdapter)context).ObjectContext;

但是我还需要类似的适配器来将我的POCO转换为EntityObject。

有什么建议吗?

谢谢。

2 个答案:

答案 0 :(得分:3)

这是 BAD 代码。

  1. 它甚至不起作用。它失败了StackOverflowException - 现在通过将您的代码段复制到我的测试解决方案中来验证。
  2. 不是级联删除。级联删除发生在数据库中(除非您已经加载了实体),但此代码始终在所有导航属性上执行查询以加载实体并在应用程序中将其标记为已删除。通过将所有这些数据从数据库传输到您的应用程序,它会产生可怕的开销。
  3. 前一段中的单词all表示all =它不尊重级联删除的正常流程(从父级到子级)。此方法也可以反向流动(从子级到父级),因为它是递归的,所以父级的导航属性也将被加载和删除。这意味着从孩子那里你可以轻松删除数据库的重要部分!!!
  4. 如果您在子实体和父实体上都有导航属性,那么您将进入无限循环!
  5. 在递归函数中调用
  6. SaveChanges - 每次执行都将从上下文中清除每个未处理的更改 - 而不仅仅是在特定递归步骤中完成的更改。如果你想把所有东西保存在单个原子操作中,它也需要TransactionScope
  7. 这种方法是引入并发问题的一种很好的方法 - 更糟糕的是 - 应用程序的死锁。
  8. 依赖于EntityObject - OMG为什么关于EF6的书包含与EntityObject类相关的代码?看起来像一个现金牛,内容从旧版本复制到EF4。我对ObjectContext API没有任何反对意见,只有EntityObject?真的?
  9. 简而言之,如果您想要级联删除或不使用级联删除和手动(最好使用直接SQL)删除依赖项,请自行帮忙并修复您的数据库和实体模型。还可以选择使用触发器来执行该SQL,但我不认为触发器是一个不错的选择。

答案 1 :(得分:0)

更好的方法是创建一个名为&#34;删除&#34;的扩展方法。在每个实体上,以及存在父/子关系的地方,嵌套那些删除调用。

例如:

public class ParentType
{
    public Int64 Id;
    public virtual List<ChildType> Children;
}

public class Child
{
    public Int64 Child;
    public string Name;
}

public static class EntityDeletions
{
    public static void Delete(this ParentType Parent, bool Commit = true)
    {
        using(var db = new DbContext())
        {
            foreach(var child in Parent.Children)
                child.Delete(false);
            db.Parents.Remove(Parent);
        }

        if(Commit)
            db.SaveChanges();        
    }

    public static void Delete(this ChildType Child, bool Commit = true)    
    {
        using(var db = new DbContext())
        {            
            db.Children.Remove(Child);
        }

        if(Commit)
            db.SaveChanges();        
    }
}

一些额外的代码,但是你确定级联删除按预期发生。请记住,如果您使用Entity Framework创建初始数据库,它还会自动为您创建级联删除触发器。但是,当您的数据库已存在时,它不会为您创建级联删除触发器。