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