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

时间:2021-04-08 15:41:08

Is there a way to cascade delete entities without modifying foreign keys in DB and without modifying edmx? I have DB with over 100 tables referenced using foreign keys with Delete Rule = No Action.

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

I found this this beautiful code in "Entity Framework 6 Recipes" book. But it for ObjectContext and I need for the DbContext.

我在“Entity Framework 6 Recipes”一书中找到了这个漂亮的代码。但它对于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();
    } 

It's possible to use this method with this convertion

可以将此方法与此转换一起使用

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

but then I also need similar adapter to convert my POCO to EntityObject.

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

Any suggestions?

有什么建议么?

Thank you.

谢谢。

2 个解决方案

#1


3  

That is BAD code.

那是BAD代码。

  1. It even doesn't work. It fails with *Exception - verified right now by copying your code snippet into my test solution.
  2. 它甚至不起作用。它失败了*Exception - 现在通过将代码片段复制到我的测试解决方案中来验证。
  3. It is not cascade delete. Cascade delete happens in database (unless you already have entities loaded) but this code always executes queries on all navigation properties to load entities and mark them as deleted in your application. It creates terrible overhead by transferring all those data from DB to your app.
  4. 它不是级联删除。级联删除发生在数据库中(除非您已经加载了实体),但此代码始终对所有导航属性执行查询以加载实体并在应用程序中将其标记为已删除。通过将所有这些数据从DB传输到您的应用程序,它会产生可怕的开销。
  5. The word all in previous paragraph really means all = it doesn't respect the normal flow of cascade delete (from parent to children). This method can also flow in reverse direction (from children to parent) and because it is recursive your parent's navigation properties will be loaded and deleted as well. It means that from child you can easily delete significant part of your database!!!
  6. 前一段中的单词all表示all =它不尊重级联删除的正常流程(从父级到子级)。此方法也可以反向流动(从子级到父级),并且因为它是递归的,所以父级的导航属性也将被加载和删除。这意味着从孩子那里你可以轻松删除数据库的重要部分!
  7. If you have navigation property on both child and parent entity you will get into infinite loop!
  8. 如果你在子实体和父实体上都有导航属性,你将进入无限循环!
  9. SaveChanges is called in recursive function - each execution will flush to database every unprocessed change from the context - not only changes done in that specific recursion step. It also requires TransactionScope if you want to keep everything in single atomic operation.
  10. 在递归函数中调用SaveChanges - 每次执行都将从上下文中清除每个未处理的更改 - 而不仅仅是在特定递归步骤中完成的更改。如果要将所有内容保存在单个原子操作中,它还需要TransactionScope。
  11. This approach is a great way to introduce concurrency issues and worse - deadlocks to your application.
  12. 这种方法是引入并发性问题的一种很好的方法 - 更糟糕的是 - 应用程序的死锁。
  13. It is dependent on EntityObject - OMG why book about EF6 contains code related to EntityObject class? Looks like a cash cow with content copied from old version about EF4. I don't have anything against ObjectContext API but EntityObject? Really?
  14. 它依赖于EntityObject - OMG为什么关于EF6的书包含与EntityObject类相关的代码?看起来像一个摇钱树,内容从旧版本复制EF4。我没有任何针对ObjectContext API但是EntityObject的东西?真?

In short make yourselves a favor and fix your DB and entity model if you want to have cascade delete or don't use cascade delete and manually (preferably with direct SQL) delete dependencies. There is also option to use triggers to execute that SQL but I don't consider triggers as a good option.

简而言之,如果您想要级联删除或不使用级联删除和手动(最好使用直接SQL)删除依赖项,请自行帮助并修复您的数据库和实体模型。还可以选择使用触发器来执行该SQL,但我不认为触发器是一个不错的选择。

#2


0  

A better approach would be to create an extension method called "Delete" on each of your entities, and where parent/child relations exist, nest those delete calls.

更好的方法是在每个实体上创建一个名为“Delete”的扩展方法,并且在存在父/子关系的情况下,嵌套这些删除调用。

For example:

例如:

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();        
    }
}

A little bit extra code, but then you are sure that cascade delete happens as intended. Keep in mind that if you use Entity Framework to create your initial database, it will also automatically create your cascade-delete triggers for you. However, it will not create cascade delete triggers for you when your database already exists.

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

#1


3  

That is BAD code.

那是BAD代码。

  1. It even doesn't work. It fails with *Exception - verified right now by copying your code snippet into my test solution.
  2. 它甚至不起作用。它失败了*Exception - 现在通过将代码片段复制到我的测试解决方案中来验证。
  3. It is not cascade delete. Cascade delete happens in database (unless you already have entities loaded) but this code always executes queries on all navigation properties to load entities and mark them as deleted in your application. It creates terrible overhead by transferring all those data from DB to your app.
  4. 它不是级联删除。级联删除发生在数据库中(除非您已经加载了实体),但此代码始终对所有导航属性执行查询以加载实体并在应用程序中将其标记为已删除。通过将所有这些数据从DB传输到您的应用程序,它会产生可怕的开销。
  5. The word all in previous paragraph really means all = it doesn't respect the normal flow of cascade delete (from parent to children). This method can also flow in reverse direction (from children to parent) and because it is recursive your parent's navigation properties will be loaded and deleted as well. It means that from child you can easily delete significant part of your database!!!
  6. 前一段中的单词all表示all =它不尊重级联删除的正常流程(从父级到子级)。此方法也可以反向流动(从子级到父级),并且因为它是递归的,所以父级的导航属性也将被加载和删除。这意味着从孩子那里你可以轻松删除数据库的重要部分!
  7. If you have navigation property on both child and parent entity you will get into infinite loop!
  8. 如果你在子实体和父实体上都有导航属性,你将进入无限循环!
  9. SaveChanges is called in recursive function - each execution will flush to database every unprocessed change from the context - not only changes done in that specific recursion step. It also requires TransactionScope if you want to keep everything in single atomic operation.
  10. 在递归函数中调用SaveChanges - 每次执行都将从上下文中清除每个未处理的更改 - 而不仅仅是在特定递归步骤中完成的更改。如果要将所有内容保存在单个原子操作中,它还需要TransactionScope。
  11. This approach is a great way to introduce concurrency issues and worse - deadlocks to your application.
  12. 这种方法是引入并发性问题的一种很好的方法 - 更糟糕的是 - 应用程序的死锁。
  13. It is dependent on EntityObject - OMG why book about EF6 contains code related to EntityObject class? Looks like a cash cow with content copied from old version about EF4. I don't have anything against ObjectContext API but EntityObject? Really?
  14. 它依赖于EntityObject - OMG为什么关于EF6的书包含与EntityObject类相关的代码?看起来像一个摇钱树,内容从旧版本复制EF4。我没有任何针对ObjectContext API但是EntityObject的东西?真?

In short make yourselves a favor and fix your DB and entity model if you want to have cascade delete or don't use cascade delete and manually (preferably with direct SQL) delete dependencies. There is also option to use triggers to execute that SQL but I don't consider triggers as a good option.

简而言之,如果您想要级联删除或不使用级联删除和手动(最好使用直接SQL)删除依赖项,请自行帮助并修复您的数据库和实体模型。还可以选择使用触发器来执行该SQL,但我不认为触发器是一个不错的选择。

#2


0  

A better approach would be to create an extension method called "Delete" on each of your entities, and where parent/child relations exist, nest those delete calls.

更好的方法是在每个实体上创建一个名为“Delete”的扩展方法,并且在存在父/子关系的情况下,嵌套这些删除调用。

For example:

例如:

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();        
    }
}

A little bit extra code, but then you are sure that cascade delete happens as intended. Keep in mind that if you use Entity Framework to create your initial database, it will also automatically create your cascade-delete triggers for you. However, it will not create cascade delete triggers for you when your database already exists.

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