实体框架核心2.0选择查询存在多对多问题

时间:2018-09-19 18:27:42

标签: .net asp.net-core entity-framework-core

下面是模型。

class Product
{
    public int Id { get; set; }
    public ICollection<Categorization> Categorization { get; set; }
}

class Categorization
{
    public int ProductId { get; set; }
    public Product Product { get; set; }

    public int CategoryId { get; set; }
    public Category Category { get; set; }
}

class Category
{
    public int Id { get; set; }
    public ICollection<Categorization> Categorization { get; set; }
}

我正尝试列出所有产品及其类别。 API代码如下

foreach (var product in _context.Products.ToList()){
    var categories = product.Categorization.Select(c => c.Category);
    ...     
}

当我们调用Api时,出现此错误:

  

System.ArgumentNullException:值不能为null。
  参数名称:source
  在System.Linq.Enumerable.Select [TSource,TResult](IEnumerable 1 source, Func 2选择器)处

4 个答案:

答案 0 :(得分:1)

product.Categorization为空,因为未加载。如果您期望延迟加载来处理加载,则必须将product.Categorization属性设为虚拟(以及Categorization类中的希望延迟加载的属性,在这种情况下为Category

编辑:在您的示例中,您应该急于使用IncludeThenInclude加载数据,因为您知道需要数据:

_context.Products
   .Include( p => p.Categorization )
   .ThenInclude( c => c.Category )
   .ToList()

答案 1 :(得分:0)

尝试将虚拟对象添加到这样的对象中:

class Product
{
    public int Id { get; set; }
    public virtual ICollection<Categorization> Categorization { get; set; }
}

class Categorization
{
    public int ProductId { get; set; }
    public virtual Product Product { get; set; }

    public int CategoryId { get; set; }
    public virtual Category Category { get; set; }
}

class Category
{
    public int Id { get; set; }
    public virtual ICollection<Categorization> Categorization { get; set; }
}

答案 2 :(得分:0)

发生错误,因为product.Categorization为空。
Entity Framework Core 2.1及更高版本支持延迟加载。请检查特定产品的分类是否为空,并尝试执行预先加载(尽管根据文档可能不需要这样做) 例如:

foreach (var product in _context.Products.Include(p => p.Categorization).ToList()){
    if (product.Categorization != null) {
        var categories = product.Categorization.Include(c => c.Category).Select(c => c.Category);
        ...     
    }
}

还请检查您是否正确配置了多对多关系,因为它要求您以这种方式定义复合主键:

override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Categorization>().HasKey(c => new { c.ProductId, c.CategoryId});
}

请查看本教程,因为它可能有用:Entity Framework Tutorial - Configure Many-to-Many Relationships

答案 3 :(得分:0)

要查询所有产品及其类别,可以尝试使用IncludeThenInclude,如下所示:

        public async Task<IActionResult> GetAllArticleAsync()
    {
        var articles = await _context.Articles
                               .Include(a => a.ArticleTags)
                               .ThenInclude(at => at.Tag)
                               .Select(a => new
                               {
                                   Id = a.Id,
                                   ArticleName = a.ArticleName,
                                   Tags = a.ArticleTags.Select(at => at.Tag).ToList()
                               })
                               .ToListAsync();
        return Ok(articles);
    }

通过这种方式,您需要像下面这样在opt.SerializerSettings.ReferenceLoopHandling中配置Startup.cs

        services.AddMvc()
                .AddJsonOptions(opt => opt.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);

有关完整的演示,请参阅EFCorePro