首页 > 解决方案 > EF Core 处理影子外键 DeleteBehaviour

问题描述

我希望能够在删除影子外键属性的相关实体时更改行为。

public class Author
{
    public int AuthorId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public ICollection<Book> Books { get; set; }
}
public class Book
{
    public int BookId { get; set; }
    public string Title { get; set; }
}

此设置将在图书实体中创建一个影子属性“AuthorId”,并且可以根据需要为空。现在我希望当我删除一个作者时,所有相关书籍都将“AuthorId”外键设置为null. 我怎样才能做到这一点?

标签: c#entity-frameworkentity-framework-core

解决方案


只需在 DbContext 中配置删除行为:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{

    modelBuilder.Entity<Book>()
        .HasOne<Author>()
        .WithMany(a => a.Books)
        .HasForeignKey("AuthorId")
        .OnDelete(DeleteBehavior.SetNull);

    base.OnModelCreating(modelBuilder);
}

例如:

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Linq;

namespace EfCore3Test
{


    public class Author
    {
        public int AuthorId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public ICollection<Book> Books { get; } = new HashSet<Book>();
    }
    public class Book
    {
        public int BookId { get; set; }
        public string Title { get; set; }
    }

    public class Db : DbContext
    {


        public DbSet<Author> Authors { get; set; }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {

            modelBuilder.Entity<Book>()
                .HasOne<Author>()
                .WithMany(a => a.Books)
                .HasForeignKey("AuthorId")
                .OnDelete(DeleteBehavior.SetNull);

            base.OnModelCreating(modelBuilder);
        }
        public static readonly ILoggerFactory MyLoggerFactory
            = LoggerFactory.Create(builder => { builder.AddConsole(); });
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("Server=localhost;Database=EFCore3Test;Integrated Security = true", a => a.UseRelationalNulls(true))
                          .ConfigureWarnings(c => c.Log((RelationalEventId.CommandExecuting, LogLevel.Information)))
                          .UseLoggerFactory(MyLoggerFactory);
            base.OnConfiguring(optionsBuilder);
        }

    }

    class Program
    {
        static void Main(string[] args)
        {
            using (var db = new Db())
            {
                db.Database.EnsureDeleted();
                db.Database.EnsureCreated();

                var a = new Author();
                for (int i = 0; i < 10; i++)
                {

                    var b = new Book();
                    a.Books.Add(b);
                }

                db.Authors.Add(a);
                db.SaveChanges();
            }





            using (var db = new Db())
            {
                var a = db.Authors.First();
                db.Authors.Remove(a);
                db.SaveChanges();

            }
        }
    }
}

对于 SQL Server,这是生成的 Book 表:

  CREATE TABLE [Book] (
      [BookId] int NOT NULL IDENTITY,
      [Title] nvarchar(max) NULL,
      [AuthorId] int NULL,
      CONSTRAINT [PK_Book] PRIMARY KEY ([BookId]),
      CONSTRAINT [FK_Book_Authors_AuthorId] FOREIGN KEY ([AuthorId]) REFERENCES [Authors] ([AuthorId]) ON DELETE SET NULL
  );

推荐阅读