文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

如何进行Entity Framework Core关联删除

2023-06-22 07:18

关注

这篇文章将为大家详细讲解有关如何进行Entity Framework Core关联删除,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

关联删除通常是一个数据库术语,用于描述在删除行时允许自动触发删除关联行的特征;即当主表的数据行被删除时,自动将关联表中依赖的数据行进行删除,或者将外键更新为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]));GOCREATE 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中支持如下四种行为:

ON DELETE NO ACTION

默认行为,删除主表数据行时,依赖表中的数据不会执行任何操作,此时会产生错误,并回滚DELETE语句。例如会产生下面的错误:

DELETE 语句与 REFERENCE 约束"FK_Order Details_Orders_OrderID"冲突。该冲突发生于数据库"Northwind_Test",表"dbo.Order Details", column 'OrderID'。

语句已终止。

ON DELETE CASCADE

删除主表数据行时,依赖表的中数据行也会同步删除。

ON DELETE SET NULL

删除主表数据行时,将依赖表中数据行的外键更新为NULL。为了满足此约束,目标表的外键列必须可为空值。

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]));GOCREATE 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语句如下:

如何进行Entity Framework Core关联删除

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

如何进行Entity Framework Core关联删除        

总结

根据上面的测试结果,我们可以出得如下结论:

DeleteBehavior.Cascade

DeleteBehavior.SetNull

DeleteBehavior.ClientSetNull

DeleteBehavior.Restrict

关于如何进行Entity Framework Core关联删除就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯