简体   繁体   English

EF Core 中的软删除嵌套实体

[英]Soft delete nested entities in EF Core

I have some nested entities, and I want to Auto soft-delete children of a record when I soft-delete that record(like hard-delete).我有一些嵌套实体,当我软删除该记录(如硬删除)时,我想自动软删除该记录的子项。 How can I do this?我怎样才能做到这一点? And what is the best approach?最好的方法是什么?

class Base
{
    bool isDeleted { set; get; }
}

class A : Base
{
    //Collection of B
}

class B : Base
{
    //Collection of C
}

class C : Base
{
    //Collection of D
}
....

For example:例如:

Table A:表 A:

    Id    ForeignKey(B Id)    isDeleted 
    -------------------------------------
    1        1                 false

Table B:表 B:

   Id    ForeignKey(C Id)    isDeleted
   -------------------------------------
    1        1                 false
    1        2                 false
    1        3                 false

Table C:表 C:

    Id    ForeignKey(D Id)    isDeleted
    -------------------------------------
    1        1                 false
    1        2                 false
    2        3                 false
    2        4                 false
    3        5                 false
    3        6                 false

Code:代码:

public void SoftDeleteA()
{
     //A.isDeleted = true;
     //???How to soft-delete related records in B,C,D ,...
     //SaveChanges();
}

Now when I soft-delete rows from A, all the rows of B and C must also be soft-deleted现在当我从 A 软删除行时,B 和 C 的所有行也必须被软删除

There is no automatic way to achieve this with entity framework.实体框架没有自动的方法来实现这一点。 Soft-delete is just a term and it doesn't actually delete the record, but only updates a single column value, so no related entities are affected with this.软删除只是一个术语,它实际上并没有删除记录,而只是更新单个列值,因此不会影响相关实体。 However, you can do this with either entity framework or SQL trigger.但是,您可以使用实体框架或 SQL 触发器来执行此操作。 Since you want this to happen automatically, create an update trigger on table A and set isDeleted in related tables from updated record.由于您希望这自动发生,请在表 A 上创建一个更新触发器,并在更新记录的相关表中设置 isDeleted。

Articles related to trigger:触发相关文章:
https://docs.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql?view=sql-server-ver15 https://docs.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql?view=sql-server-ver15
https://www.tutorialgateway.org/after-update-triggers-in-sql-server/ https://www.tutorialgateway.org/after-update-triggers-in-sql-server/
https://www.sqlshack.com/triggers-in-sql-server/ https://www.sqlshack.com/triggers-in-sql-server/
https://www.aspsnippets.com/Articles/Simple-Insert-Update-and-Delete-Triggers-in-SQL-Server-with-example.aspx https://www.aspsnippets.com/Articles/Simple-Insert-Update-and-Delete-Triggers-in-SQL-Server-with-example.aspx

With entity framework, you need fetch your parent along with all children first, modify them individually and save to database.使用实体框架,您需要首先获取您的父级和所有子级,单独修改它们并保存到数据库。

Example:例子:

public A FetchA()
{
  return _context.A
          .Include(a=>a.CollectionB)
          .ThenInclude(b=>b.CollectionC)
          .FirstOrDefaultAsync();
}

public void SoftDeleteA()
{
    var a = FetchA();
    if(a !=null)
    {
       a.isDeleted = true;

       // loop through all related records and update them
       if(a.CollectionB?.Any()== true)
       { 
           foreach(var itemB in a.CollectionB)
           {
               itemB.isDeleted = true;

               // loop through all related records and update them
               if(itemB.CollectionC?.Any()== true)
               { 
                   foreach(var itemC in itemB.CollectionC)
                   {
                       itemC.isDeleted = true;
                   }         
               }
           }
       }

       // save changes at last
       _context.Update(a);
       await _context.SaveChangesAsync() ;
    }

}

OR if you have option to use SQL, just run the raw sql which is way faster than doing with EF.或者,如果您可以选择使用 SQL,只需运行原始 sql,这比使用 EF 快得多。

Example:例子:

update b
set isDeleted = a.isDeleted
from B b
inner join A a on b.ID = a.ID

I'm using something like Recursive Functions ;我正在使用类似Recursive Functions的东西;

class Base
{
      public virtual bool IsDeleted { get; set; }
      public virtual void DeleteMethod(int modifiedBy)
      {
          IsDeleted = true;
          ModifiedMethod(modifiedBy);
      }
}

class A : Base
{
    //Collection of B
    
    public override void DeleteMethod(int modifiedBy)
    {
        B.ForEach(oe => oe.DeleteMethod(modifiedBy));
        base.DeleteMethod(modifiedBy);
    }
}

class B : Base
{
    //Collection of C
    
    public override void DeleteMethod(int modifiedBy)
    {
        C.ForEach(oe => oe.DeleteMethod(modifiedBy));
        base.DeleteMethod(modifiedBy);
    }
}

class C : Base
{
    //Collection of D
    
    public override void DeleteMethod(int modifiedBy)
    {
        D.ForEach(oe => oe.DeleteMethod(modifiedBy));
        base.DeleteMethod(modifiedBy);
    }
}

when called some {ParentClass}.DeleteMethod() , its start operations to child classes.当调用一些{ParentClass}.DeleteMethod()时,它开始对子类进行操作。 its same thing above answer but covering all inherited classes, not need write loop again every methods.上面的答案相同,但涵盖了所有继承的类,不需要每个方法再次编写循环。

public async Task SoftDeleteAsync()
{
    ..
    A.DeleteMethod(userid);
    await context.SaveChangesAsync();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM