GPT4.0+Midjourney绘画+国内大模型 会员永久免费使用!
 【 如果你想靠AI翻身,你先需要一个靠谱的工具! 】
关联删除通常是一个数据库术语,用于描述在删除行时允许自动触发删除关联行的特征;即当主表的数据行被删除时,自动将关联表中依赖的数据行进行删除,或者将外键更新为NULL或默认值。
我们先来看一看SQL Server中支持的行为。在创建外键约束时,可以指定关联表在主表删除行时,对依赖的数据如何执行操作。例如下面的SQL语句,[Order Details]表中[OrderID]字段 是外键,依赖于[Orders]表中的主键[OrderID]。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | CREATETABLE[Orders] (    [OrderID] intNOTNULLIDENTITY,    [Name] nvarchar(max) NULL,    [OrderDate] datetime2 NULL,    CONSTRAINT[PK_Orders] PRIMARYKEY([OrderID]));GOCREATETABLE[OrderDetails] (    [DetailId] intNOTNULLIDENTITY,    [OrderID] intNULL,    [ProductID] intNOTNULL,    CONSTRAINT[PK_Order Details] PRIMARYKEY([DetailId]),    CONSTRAINT[FK_Order Details_Orders_OrderID] FOREIGNKEY([OrderID]) REFERENCES[Orders] ([OrderID]) ONDELETESETNULL); | 
外键约束[FK_Order Details_Orders_OrderID]末尾的语句是ON DELETE SET NULL,表示当主表的数据行删除时,自动将关联表数据行的外键更新为NULL。
在SQL Server中支持如下四种行为:
1.ON DELETE NO ACTION
默认行为,删除主表数据行时,依赖表中的数据不会执行任何操作,此时会产生错误,并回滚DELETE语句。例如会产生下面的错误:
DELETE 语句与 REFERENCE 约束"FK_Order Details_Orders_OrderID"冲突。该冲突发生于数据库"Northwind_Test",表"dbo.Order Details", column 'OrderID'。
语句已终止。
2.ON DELETE CASCADE
删除主表数据行时,依赖表的中数据行也会同步删除。
3.ON DELETE SET NULL
删除主表数据行时,将依赖表中数据行的外键更新为NULL。为了满足此约束,目标表的外键列必须可为空值。
4.ON DELETE SET DEFAULT
删除主表数据行时,将依赖表的中数据行的外键更新为默认值。为了满足此约束,目标表的所有外键列必须具有默认值定义;如果外键可为空值,并且未显式设置默认值,则将使用NULL作为该列的隐式默认值。
简单介绍了数据库中行为后,我们来着重介绍 EF Core 中的关联实体的行为。
我们先定义两个实体Order、OrderDetail分别表示订单和订单明细;其中Order与OrderDetail的关系是一对多,在OrderDetail实体中OrderID表示外键,依赖于Order实体中的主键OrderID。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | publicclassOrder{    publicintOrderID { get; set; }    publicstringName { get; set; }    publicDateTime? OrderDate { get; set; }    publicICollection<OrderDetail> OrderDetails { get; set; }}publicclassOrderDetail{    publicintDetailId { get; set; }    publicint? OrderID { get; set; }        publicintProductID { get; set; }    publicOrder Order { get; set; }} | 
在DbContext中OnModelCreating方法中,我们使用 Fluent API 配置实体中之间的关系。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | publicclassNorthwindContext : DbContext{    publicvirtualDbSet<Order> Orders { get; set; }    publicvirtualDbSet<OrderDetail> OrderDetails { get; set; }    protectedoverridevoidOnModelCreating(ModelBuilder modelBuilder)    {        modelBuilder.Entity<Order>(            builder =>            {                builder.HasMany<OrderDetail>(e => e.OrderDetails).WithOne(e => e.Order).HasForeignKey(e => e.OrderID).OnDelete(DeleteBehavior.ClientSetNull);            });    }} | 
在OnDelete方法中,需要传递参数DeleteBehavior枚举,分别有如下四个值:
| 1 2 3 4 5 6 7 8 9 10 | publicenumDeleteBehavior{    Cascade,    SetNull,    ClientSetNull,    Restrict}     | 
这四个枚举值的分别表示不同的行为,这也是我们今天的重点。
我们分别使用使用这这个枚举值,来创建数据表结构。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | [InlineData(DeleteBehavior.Cascade)][InlineData(DeleteBehavior.SetNull)] [InlineData(DeleteBehavior.ClientSetNull)][InlineData(DeleteBehavior.Restrict)][Theory]publicvoidCreate_Database(DeleteBehavior behavior){    using(var northwindContext = newNorthwindContext(behavior))    {        northwindContext.Database.EnsureDeleted();        northwindContext.Database.EnsureCreated();    }} | 
四个枚举值创建表的SQL语句类似如下,唯一区别在于创建外键约束[FK_Order Details_Orders_OrderID]中ON DELETE {}后面的语句。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | CREATETABLE[Orders] (    [OrderID] intNOTNULLIDENTITY,    [Name] nvarchar(max) NULL,    [OrderDate] datetime2 NULL,    CONSTRAINT[PK_Orders] PRIMARYKEY([OrderID]));GOCREATETABLE[OrderDetails] (    [DetailId] intNOTNULLIDENTITY,    [OrderID] intNOTNULL,    [ProductID] intNOTNULL,    CONSTRAINT[PK_Order Details] PRIMARYKEY([DetailId]),    CONSTRAINT[FK_Order Details_Orders_OrderID] FOREIGNKEY([OrderID]) REFERENCES[Orders] ([OrderID]) ONDELETECASCADE); | 
四个枚举值分别对应的SQL语句如下:

我们分别通过枚举值与是否跟踪关联实体,进行代码测试,测试代码如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | [InlineData(DeleteBehavior.Cascade, true)][InlineData(DeleteBehavior.Cascade, false)][InlineData(DeleteBehavior.SetNull, true)][InlineData(DeleteBehavior.SetNull, false)][InlineData(DeleteBehavior.ClientSetNull, true)][InlineData(DeleteBehavior.ClientSetNull, false)][InlineData(DeleteBehavior.Restrict, true)][InlineData(DeleteBehavior.Restrict, false)][Theory]publicvoidExecute(DeleteBehavior behavior, boolincludeDetail){    using(var northwindContext = newNorthwindContext(behavior))    {        northwindContext.Database.EnsureDeleted();        northwindContext.Database.EnsureCreated();    }    intorderId;    intdetailId;    using(var northwindContext = newNorthwindContext(behavior))    {        var order = newOrder {            Name = "Order1"        };        var orderDetail = newOrderDetail {            ProductID = 11        };        order.OrderDetails = newList<OrderDetail> {            orderDetail        };        northwindContext.Set<Order>().Add(order);                        northwindContext.SaveChanges();        orderId = order.OrderID;        detailId = orderDetail.DetailId;    }    using(var northwindContext = newNorthwindContext(behavior))    {        var queryable = northwindContext.Set<Order>().Where(e => e.OrderID == orderId);        if(includeDetail){            queryable = queryable.Include(e => e.OrderDetails);        }        var order = queryable.Single();         northwindContext.Set<Order>().Remove(order);        try        {            northwindContext.SaveChanges();            DumpSql();        }        catch(Exception)        {            DumpSql();            throw;        }    }    using(var northwindContext = newNorthwindContext(behavior))    {        var orderDetail = northwindContext.Set<OrderDetail>().Find(detailId);        if(behavior == DeleteBehavior.Cascade)        {            Assert.Null(orderDetail);        }        else        {            Assert.NotNull(orderDetail);        }    }}  | 
 
        
根据上面的测试结果,我们可以出得如下结论:
以上就是Entity Framework Core关联删除的详细内容,更多关于Entity Framework关联删除的资料请关注脚本之家其它相关文章!