下面是模型。
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](IEnumerable1 source, Func
2选择器)处
答案 0 :(得分:1)
product.Categorization
为空,因为未加载。如果您期望延迟加载来处理加载,则必须将product.Categorization
属性设为虚拟(以及Categorization
类中的希望延迟加载的属性,在这种情况下为Category
)
编辑:在您的示例中,您应该急于使用Include
和ThenInclude
加载数据,因为您知道需要数据:
_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)
要查询所有产品及其类别,可以尝试使用Include
和ThenInclude
,如下所示:
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