c# - 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”的实体上的主键。
在此先感谢您的帮助!
解决方案
您实际上可以使用自动生成的连接表,并且仍然可以获得每本书售出的数量,而无需完全加载 users。
使用您的当前User
和Book
模型,将关系配置为 -
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();
编辑:
您可以使用AutoMapper
which 可以为您进行投影.Select()
,例如 -
var dtos = _Mapper.ProjectTo<BookDTO>(dbCtx.Books).ToList();
为此,您需要 -
- 从查询结果中创建具有所需属性的 DTO 模型,例如 -
public class BookDTO
{
public int Id { get; set; }
public string Author { get; set; }
public int UsersReached { get; set; }
}
- 定义从
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]
属性。UsersReached
Book
推荐阅读
- mysql - MySQL中的并行存储过程执行
- vba - Access VBA中的表单使用函数从网络ID设置字段
- html - 如何在不降低图像质量的情况下加载图像而不影响我的网站的加载速度
- jasper-reports - 如何更改饼图中的颜色(jaspersoft 工作室)
- python - 如何使用函数过滤数据框?
- git - Git 搞乱头和大师
- django - 如何在 Django admin 中显示正确的名称对象而不是“XXX 对象”
- python - 如何在保持结构的同时写入预先存在的 xml 文件?
- php - PluginManager::get 无法获取或创建 FileQueryPlugin 的实例
- hyperledger-fabric - 订购者是否存储所有区块链?