EF Core-不加载所有子实体

时间:2020-01-23 05:28:18

标签: c# .net-core entity-framework-core

我有3个实体:

public partial class Category
{
    public int CategoryID { get; set; }
    public string? CategoryName { get; set; }

    public ICollection<BookCategory> BookCategory { get; set; }
}

public partial class BookCategory
{
    public int CategoryID { get; set; }
    public int BookID { get; set; }

    public Category Category { get; set; }
    public Book Book { get; set; }
}

public partial class Book
{
    public int BookID { get; set; }
    public string? Title { get; set; }
}

我希望返回一个Category数组,一个BookCategory子数组与Book一一对应。

使用这样的呼叫;

public async Task<List<Category>> test()
{
    var query = dbContext.Category
                .Include(p => p.BookCategory) 
                .ThenInclude(pc => pc.Book)
                .OrderBy(p => p.CategoryID) as IQueryable<Category>;

    var data = await query.ToListAsync();

    return data;
}

我有这样的伪数据:

insert into kiosk.Category (CategoryID, CategoryName) values (1, 'Horror')
insert into kiosk.Category (CategoryID, CategoryName) values (2, 'Fantasy')

insert into kiosk.Book (BookID, Title) values (1, 'Space shooty')
insert into kiosk.Book (BookID, Title) values (2, 'Elf shooty')

insert into kiosk.BookCategory (BookID, CategoryID) values (1, 2)
insert into kiosk.BookCategory (BookID, CategoryID) values (2, 2)

但是,我收到的该请求的响应仅给我一个类别2的记录,而不是预期的两个。

[
    {
        "categoryID": 1,
        "categoryName": "Horror",
        "bookCategory": []
    },
    {
        "categoryID": 2,
        "categoryName": "Fantasy",
        "bookCategory": [
            {
                "categoryID": 2,
                "bookID": 1,
                "book": {
                    "bookID": 1,
                    "title": "Space shooty"
                }
            }
        ]
    }
]

DBContext:

    public class BooksDbContext : DbContext
    {

        public DbSet<Book> book { get; set; } 
        public DbSet<Category> Category { get; set; } 
        public DbSet<BookCategory> BookCategory { get; set; } 

        public BooksDbContext()
        { }

        public BooksDbContext(DbContextOptions options) : base(options)
        { }

        public BooksDbContext(string connectionString)
        {
            this.connectionString = connectionString;
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.HasDefaultSchema("dbo");

            modelBuilder.ApplyConfiguration(new BookCategoryConfiguration());
            modelBuilder.ApplyConfiguration(new CategoryTestConfiguration());
            modelBuilder.ApplyConfiguration(new BookConfiguration());

        }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder);
            if (!string.IsNullOrWhiteSpace(connectionString))
            {
                optionsBuilder.UseSqlServer(connectionString);
            }
        }
    }

三种配置如下

    public class BookCategoryConfiguration : IEntityTypeConfiguration<BookCategory>
    {
        public void Configure(EntityTypeBuilder<BookCategory> builder)
        {
            builder.ToTable("BookCategory");
            builder.HasKey(x => x.BookID);
            builder.HasKey(x => x.CategoryID);         

            builder.HasOne(a => a.Category).WithMany(b => b.BookCategory).HasForeignKey(c => c.CategoryID); // FK_POSCategoryProduct_POSCategory
        }
    }


    public class CategoryTestConfiguration : IEntityTypeConfiguration<Category>
    {
        public void Configure(EntityTypeBuilder<Category> builder)
        {
            builder.ToTable("Category");
            builder.HasKey(x => x.CategoryID);

            builder.Property(x => x.CategoryID).HasColumnName(@"CategoryID").HasColumnType("int").IsRequired();
            builder.Property(x => x.CategoryName).HasColumnName(@"CategoryName").HasColumnType("nvarchar").HasMaxLength(50);          

        }
    }


    public class BookConfiguration : IEntityTypeConfiguration<Book>
    {
        public void Configure(EntityTypeBuilder<Book> builder)
        {
            builder.ToTable("Book");
            builder.HasKey(x => x.BookID);

            builder.Property(x => x.BookID).HasColumnName(@"BookID").HasColumnType("int").IsRequired();
            builder.Property(x => x.Title).HasColumnName(@"Title").HasColumnType("nvarchar").HasMaxLength(50);
        }
    }

1 个答案:

答案 0 :(得分:5)

该模型通过显式连接实体表示标准的多对多关系。

问题在于连接实体键的流利映射:

builder.HasKey(x => x.BookID);
builder.HasKey(x => x.CategoryID);

HasKey方法(大多数(如果不是全部)流畅的API)不是 加法。稍后的呼叫将获胜(替换先前的呼叫)。

以上代码的作用是EF Core认为CategoryIDBookCategory表的 unique 键,因此每个{{1} }。

当然,我们的想法是定义联​​接实体的标准组合主键。通过使用匿名类型(如EF Core Keys文档主题的复合键部分示例所示)可以实现这一点(类似于所有允许多个属性的流利API)。

将其应用于您的方案将用替换上述两行

CategoryID
相关问题