EFCore 配置多对多关联

在 C# 和 Entity Framework Core (EF Core) 中处理多对多关系非常常见。这种关系类型通常涉及到一个关联表(也称为交叉引用表或连接表),该表用于存储两个实体之间的关联。

例子场景

假设我们有两个实体:Author 和 Book,并且一位作者可以写多本书,一本书也可以有多个作者。为了表示这种关系,我们需要创建一个连接表来存储作者和书籍之间的关系。

步骤 1: 定义实体类

首先定义 Author 和 Book 类:

csharp 复制代码
public class Author
{
    public int Id { get; set; }
    public string Name { get; set; }

    // 导航属性
    public ICollection<Book> Books { get; set; } = new HashSet<Book>();
}

public class Book
{
    public int Id { get; set; }
    public string Title { get; set; }

    // 导航属性
    public ICollection<Author> Authors { get; set; } = new HashSet<Author>();
}

步骤 2: 在 DbContext 中配置关系

在你的 DbContext 类中使用 HasMany().WithMany() 来配置多对多关系:

csharp 复制代码
public class MyDbContext : DbContext
{
    public DbSet<Author> Authors { get; set; }
    public DbSet<Book> Books { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // 配置多对多关系
        modelBuilder.Entity<Author>()
            .HasMany(a => a.Books)
            .WithMany(b => b.Authors)
            .UsingEntity<AuthorBook>(
                ab => ab.HasOne(b => b.Book).WithMany().HasForeignKey(ab => ab.BookId),
                ab => ab.HasOne(a => a.Author).WithMany().HasForeignKey(ab => ab.AuthorId));

        modelBuilder.Entity<AuthorBook>()
            .HasKey(ab => new { ab.AuthorId, ab.BookId });
    }
}

// 这是用于表示多对多关系的连接实体
public class AuthorBook
{
    public int AuthorId { get; set; }
    public Author Author { get; set; }

    public int BookId { get; set; }
    public Book Book { get; set; }
}

步骤 3: 增删改查操作

接下来,我们来具体看下如何执行基本的 CRUD 操作。

插入

插入数据可以通过添加实体到导航属性集合中来实现:

csharp 复制代码
using (var db = new MyDbContext())
{
    var author = new Author { Name = "John Doe" };
    var book = new Book { Title = "Learning EF Core" };

    // 添加双向关联
    author.Books.Add(book);
    book.Authors.Add(author);

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

查询

查询操作可以通过导航属性进行:

csharp 复制代码
using (var db = new MyDbContext())
{
    var author = db.Authors.Include(a => a.Books).FirstOrDefault(a => a.Name == "John Doe");

    // 打印作者的所有书籍标题
    foreach (var book in author.Books)
    {
        Console.WriteLine(book.Title);
    }
}

更新

更新操作通常涉及修改导航属性:

csharp 复制代码
using (var db = new MyDbContext())
{
    var author = db.Authors.Include(a => a.Books).FirstOrDefault(a => a.Name == "John Doe");
    var newBook = new Book { Title = "Advanced EF Core" };

    // 添加新的关联
    author.Books.Add(newBook);
    newBook.Authors.Add(author);

    db.SaveChanges();
}

删除

删除关联可以通过移除导航属性中的元素来完成:

csharp 复制代码
using (var db = new MyDbContext())
{
    var author = db.Authors.Include(a => a.Books).FirstOrDefault(a => a.Name == "John Doe");
    var bookToRemove = author.Books.FirstOrDefault(b => b.Title == "Learning EF Core");

    if (bookToRemove != null)
    {
        // 移除双向关联
        author.Books.Remove(bookToRemove);
        bookToRemove.Authors.Remove(author);

        db.SaveChanges();
    }
}
相关推荐
鸠摩智首席音效师12 天前
如何在 macOS 上安装 .NET Core ?
macos·.netcore
宝桥南山16 天前
Microsoft Agent Framework(MAF) - 如何将workflow或者A2A client转换成一个AI Agent
microsoft·ai·微软·aigc·.net·.netcore
滴滴答答哒1 个月前
.NET Core 基于 AOP + Polly 实现数据库死锁自动重试
数据库·.netcore·sqlsugar
.NET修仙日记1 个月前
.NET EFCore批量插入性能优化实战:30秒 → 0.5秒
性能优化·c#·.net·.netcore·微软技术·efcore·踩坑实录
Kimhill张1 个月前
.net core8 WPF 依赖注入(DI)
wpf·.netcore
wangl_921 个月前
C# / .NET 在工业环境中的优势
开发语言·c#·.net·.netcore·.net core·visual studio
豆豆1 个月前
信创环境下CMS国产化适配实践:以.NET Core路线为例的技术验证
.netcore·cms·信创·国产化·建站系统·内容管理系统·网站管理系统
时光追逐者1 个月前
C#/.NET/.NET Core技术前沿周刊 | 第 70 期(2026年5.01-5.10)
c#·.net·.netcore
van久1 个月前
Day20:AutoMapper 对象映射
.netcore
van久1 个月前
Day23 登录 + 颁发 Token(DDD 四层架构 + 企业标准)
.netcore