首页 > 解决方案 > EF Core - 多对多关系使用/访问自定义连接表

问题描述

我正在尝试实现多对多关系。

模型 -

public class User
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Book> OwnedBooks { get; set; }
}

public class Own
{
    public int UserId { get; set; }
    public int BookId { get; set; }
    public User User { get; set; }
    public Book Book { get; set; }
}

public class Book
{
    [Key]
    public int Id { get; set; }
    public int AuthorId { get; set; }
    public User Author { get; set; }
    public List<User> OwnedBy { get; set; } //Not really needed, but without it I can't create the join table "Own"
    [NotMapped]
    public int UsersReached; //Get this via the "Own" table
}

DbContext -

public class TestContext : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Book> Books { get; set; }
    public DbSet<Own> Own { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseSqlServer("Server=DESKTOP-BT4H8CA;Database=Test;Trusted_Connection=True");

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.Entity<Book>().HasOne(x => x.Author);

        builder.Entity<User>()
            .HasMany(x => x.OwnedBooks)
            .WithMany(x => x.OwnedBy)
            .UsingEntity(x => x.ToTable("Own"));

        builder.Entity<Own>()
            .HasKey(x => new {x.BookId, x.UserId});
    }
}

我正在努力访问连接表“Own”。我需要它来获取每本书的销售量,而无需完全加载用户。这就是为什么我不想使用自动生成的:

不能将表 'Own' 用于实体类型 'BookUser (Dictionary<string, object>)',因为它正在用于实体类型 'Own' 和可能的其他实体类型,但没有链接关系。将外键添加到主键属性上的“BookUser (Dictionary<string, object>)”并指向另一个类型为“Own”的实体上的主键。

在此先感谢您的帮助!

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

解决方案


您实际上可以使用自动生成的连接表,并且仍然可以获得每本书售出的数量,而无需完全加载 users

使用您的当前UserBook模型,将关系配置为 -

protected override void OnModelCreating(ModelBuilder builder)
{
    builder.Entity<Book>()
        .HasOne(p => p.Author)
        .WithMany()
        .HasForeignKey(p => p.AuthorId)
        .OnDelete(DeleteBehavior.NoAction);

    builder.Entity<User>()
        .HasMany(p => p.OwnedBooks)
        .WithMany(p => p.OwnedBy);
}

然后,您可以查询书籍的销售数量为 -

var books = dbCtx.Books
        .Select(p => new Book
        {
            Id = p.Id,
            AuthorId = p.AuthorId,
            Author = p.Author,
            UsersReached = p.OwnedBy.Count  // this will not load User entities
        })
        .ToList();

编辑:
您可以使用AutoMapperwhich 可以为您进行投影.Select(),例如 -

var dtos = _Mapper.ProjectTo<BookDTO>(dbCtx.Books).ToList();

为此,您需要 -

  1. 从查询结果中创建具有所需属性的 DTO 模型,例如 -
public class BookDTO
{
    public int Id { get; set; }
    public string Author { get; set; }
    public int UsersReached { get; set; }
}
  1. 定义从Book到的地图BookDTO-
CreateMap<Book, BookDTO>()
    .ForMember(d => d.Author, opt => opt.MapFrom(s => s.Author.Name))
    .ForMember(d => d.UsersReached, opt => opt.MapFrom(s => s.OwnedBy.Count));

您可以从模型中删除该[NotMapped]属性。UsersReachedBook


推荐阅读