在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
关联删除通常是一个数据库术语,用于描述在删除行时允许自动触发删除关联行的特征;即当主表的数据行被删除时,自动将关联表中依赖的数据行进行删除,或者将外键更新为NULL或默认值。 数据库关联删除行为我们先来看一看SQL Server中支持的行为。在创建外键约束时,可以指定关联表在主表删除行时,对依赖的数据如何执行操作。例如下面的SQL语句,[Order Details]表中[OrderID]字段 是外键,依赖于[Orders]表中的主键[OrderID]。 CREATE TABLE [Orders] ( [OrderID] int NOT NULL IDENTITY, [Name] nvarchar(max) NULL, [OrderDate] datetime2 NULL, CONSTRAINT [PK_Orders] PRIMARY KEY ([OrderID]) ); GO CREATE TABLE [Order Details] ( [DetailId] int NOT NULL IDENTITY, [OrderID] int NULL, [ProductID] int NOT NULL, CONSTRAINT [PK_Order Details] PRIMARY KEY ([DetailId]), CONSTRAINT [FK_Order Details_Orders_OrderID] FOREIGN KEY ([OrderID]) REFERENCES [Orders] ([OrderID]) ON DELETE SET NULL ); 外键约束[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。 public class Order { public int OrderID { get; set; } public string Name { get; set; } public DateTime? OrderDate { get; set; } public ICollection<OrderDetail> OrderDetails { get; set; } } public class OrderDetail { public int DetailId { get; set; } public int? OrderID { get; set; } public int ProductID { get; set; } public Order Order { get; set; } } Fluent API 配置关联实体在DbContext中OnModelCreating方法中,我们使用 Fluent API 配置实体中之间的关系。 public class NorthwindContext : DbContext { public virtual DbSet<Order> Orders { get; set; } public virtual DbSet<OrderDetail> OrderDetails { get; set; } protected override void OnModelCreating(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枚举,分别有如下四个值: public enum DeleteBehavior { Cascade, SetNull, ClientSetNull, Restrict } 这四个枚举值的分别表示不同的行为,这也是我们今天的重点。 创建表结构我们分别使用使用这这个枚举值,来创建数据表结构。 [InlineData(DeleteBehavior.Cascade)] [InlineData(DeleteBehavior.SetNull)] [InlineData(DeleteBehavior.ClientSetNull)] [InlineData(DeleteBehavior.Restrict)] [Theory] public void Create_Database(DeleteBehavior behavior) { using (var northwindContext = new NorthwindContext(behavior)) { northwindContext.Database.EnsureDeleted(); northwindContext.Database.EnsureCreated(); } } 四个枚举值创建表的SQL语句类似如下,唯一区别在于创建外键约束[FK_Order Details_Orders_OrderID]中ON DELETE {}后面的语句。 CREATE TABLE [Orders] ( [OrderID] int NOT NULL IDENTITY, [Name] nvarchar(max) NULL, [OrderDate] datetime2 NULL, CONSTRAINT [PK_Orders] PRIMARY KEY ([OrderID]) ); GO CREATE TABLE [Order Details] ( [DetailId] int NOT NULL IDENTITY, [OrderID] int NOT NULL, [ProductID] int NOT NULL, CONSTRAINT [PK_Order Details] PRIMARY KEY ([DetailId]), CONSTRAINT [FK_Order Details_Orders_OrderID] FOREIGN KEY ([OrderID]) REFERENCES [Orders] ([OrderID]) ON DELETE CASCADE ); 四个枚举值分别对应的SQL语句如下: EF Core 关联实体删除行为我们分别通过枚举值与是否跟踪关联实体,进行代码测试,测试代码如下: [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] public void Execute(DeleteBehavior behavior, bool includeDetail) { using (var northwindContext = new NorthwindContext(behavior)) { northwindContext.Database.EnsureDeleted(); northwindContext.Database.EnsureCreated(); } int orderId; int detailId; using (var northwindContext = new NorthwindContext(behavior)) { var order = new Order { Name = "Order1" }; var orderDetail = new OrderDetail { ProductID = 11 }; order.OrderDetails = new List<OrderDetail> { orderDetail }; northwindContext.Set<Order>().Add(order); northwindContext.SaveChanges(); orderId = order.OrderID; detailId = orderDetail.DetailId; } using (var northwindContext = new NorthwindContext(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 = new NorthwindContext(behavior)) { var orderDetail = northwindContext.Set<OrderDetail>().Find(detailId); if (behavior == DeleteBehavior.Cascade) { Assert.Null(orderDetail); } else { Assert.NotNull(orderDetail); } } }
总结根据上面的测试结果,我们可以出得如下结论: DeleteBehavior.Cascade
DeleteBehavior.SetNull
DeleteBehavior.ClientSetNull
DeleteBehavior.Restrict
以上就是Entity Framework Core关联删除的详细内容,更多关于Entity Framework关联删除的资料请关注极客世界其它相关文章! |
请发表评论