【EF Core】如何忽略影响导航属性(级联)

文章目录

EF更新和插入时如何忽略更新导航属性

  1. 使用Ignore方法:
csharp 复制代码
modelBuilder.Entity<Blog>()
    .Ignore(b => b.Posts);
  1. 使用HasNoKey方法:
csharp 复制代码
modelBuilder.Entity<Blog>()
    .HasNoKey();
  1. 使用HasNoNavigation方法:
csharp 复制代码
modelBuilder.Entity<Blog>()
    .HasNoNavigation(b => b.Posts);
  1. 使用HasNoRelationship方法:
csharp 复制代码
modelBuilder.Entity<Blog>()
    .HasNoRelationship(b => b.Posts);

级联删除

删除主体/父实体

请考虑此简单模型,其中 Blog 是与 Post(依赖实体/子实体)的关系中的主体/父实体。 Post.BlogId 是一个外键属性,其值必须与该文章所属博客中的 Blog.Id 主键匹配。

csharp 复制代码
public class Blog
{
    public int Id { get; set; }

    public string Name { get; set; }

    public IList<Post> Posts { get; } = new List<Post>();
}

public class Post
{
    public int Id { get; set; }

    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

按照约定,由于 Post.BlogId 外键属性是不可为 null 的,因此该关系被配置为必需的。 默认情况下,所需的关系配置为使用级联删除。 要详细了解建模关系,请参阅关系。

删除博客时,所有文章都将被级联删除。 例如:

csharp 复制代码
using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

context.Remove(blog);

context.SaveChanges();

SaveChanges 以 SQL Server 为例,生成以下 SQL:

csharp 复制代码
-- Executed DbCommand (1ms) [Parameters=[@p0='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Posts]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

-- Executed DbCommand (0ms) [Parameters=[@p0='2'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Posts]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

-- Executed DbCommand (2ms) [Parameters=[@p1='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Blogs]
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

断开关系

我们不会删除博客,而是断开每篇文章与其博客之间的关系。 为此,可将每篇文章的引用导航 Post.Blog 设置为 null:

csharp 复制代码
using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

foreach (var post in blog.Posts)
{
    post.Blog = null;
}

context.SaveChanges();

还可通过从 Blog.Posts 集合导航中删除每篇文章内容来断开关系:

csharp 复制代码
using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

blog.Posts.Clear();

context.SaveChanges();

无论哪种情况,结果都一样:没有删除博客,但是删除了不再与任何博客关联的文章:

csharp 复制代码
-- Executed DbCommand (1ms) [Parameters=[@p0='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Posts]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

-- Executed DbCommand (0ms) [Parameters=[@p0='2'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Posts]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

删除不再与任何主体/依赖实体关联的实体这一行为被称作"删除孤立项"。

级联删除和删除孤立项是密切相关的。 当断开与所需的主体/父实体之间的关系时,两者都将导致删除依赖实体/子实体。 对于级联删除,由于主体/父实体本身已删除,因此发生了这种断开。 对于孤立项,主体/父实体仍然存在,但不再与依赖实体/子实体相关。

配置级联行为

使用 OnModelCreating 中的 OnDelete 方法按关系配置级联行为。 例如:

csharp 复制代码
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<Blog>()
        .HasOne(e => e.Owner)
        .WithOne(e => e.OwnedBlog)
        .OnDelete(DeleteBehavior.ClientCascade);
}

OnDelete 从公认地令人混淆的 DeleteBehavior 枚举中接受一个值。 该枚举既定义了 EF Core 在跟踪实体上的行为,又定义了使用 EF 创建架构时数据库中级联删除的配置。

来源

EF更新和插入时如何忽略更新导航属性
级联删除

相关推荐
△曉風殘月〆4 天前
C#如何简单地组合linq查询条件
c#·linq·ef
yangshuquan2 个月前
分享一个 .NET EF6 应用二级缓存提高性能的方法
性能优化·c#·.net·ef
yangshuquan2 个月前
分享 2 个 .NET EF 6 只更新某些字段的方法
c#·.net·ef
yangshuquan2 个月前
分享一个 .NET EF 6 扩展 Where 的方法
c#·.net·linq·ef
yangshuquan2 个月前
分享 .NET EF6 查询并返回树形结构数据的 2 个思路和具体实现方法
c#·.net·linq·ef
yangshuquan2 个月前
分享一个 .NET 通过监听器拦截 EF 消息写日志的详细例子
c#·.net·拦截器·ef
goyeer4 个月前
【.NET Core】你认识Attribute之CallerMemberName、CallerFilePath、CallerLineNumber三兄弟
开发语言·microsoft·c#·.netcore·ef
goyeer5 个月前
【Entity Framework】你知道如何处理无键实体吗
数据库·microsoft·c#·.netcore·ef
goyeer5 个月前
【Entity Framework】EF连接字符串和模型
microsoft·c#·asp.net·.netcore·ef
goyeer6 个月前
【Entity Framework】EF中的增删改查
c#·asp.net·.netcore·ef