我的包含始终为空。尽管我可以在SQL数据库中看到父级和子级之间的链接。
IQueryable<ManageProductItems> models = db.Products
.Include(m => m.Collections).Include(m => m.Images)
.Include(m => m.VariantDetails.Select(x => x.Variants.Select(z => z.VariantType)))
.Select....
我要包含嵌套的Products -> VariantDetails -> Variants -> VariantType
结果总是给我Variants = null
。
这是模型配置:
public class Product
{
...
public ICollection<ProductCollection> Collections { get; set; }
public ICollection<ProductVariantDetail> VariantDetails { get; set; }
public ICollection<ProductImage> Images { get; set; }
public ICollection<ProductVariantType> ProductVariantTypes { get; set; }
public ICollection<ProductVariant> ProductVariants { get; set; }
}
public class ProductVariantDetail
{
....
public ICollection<ProductVariant> Variants { get; set; }
[ForeignKey("Product")]
public Guid ProductId { get; set; }
[CascadeDelete]
public virtual Product Product { get; set; }
public virtual ProductImage ProductImage { get; set; }
}
public class ProductVariant
{
...
[ForeignKey("VariantType")]
public Guid VariantTypeId { get; set; }
[CascadeDelete]
public virtual ProductVariantType VariantType { get; set; }
public ICollection<ProductVariantDetail> VariantDetails { get; set; }
[ForeignKey("Product")]
public Guid? ProductId { get; set; }
public Product Product { get; set; }
}
public class ProductVariantType
{
...
[ForeignKey("Product")]
public Guid? ProductId { get; set; }
public Product Product { get; set; }
}
SQL服务器中有dbo.ProductVariantDetailProductVariants
表,它们映射ProductVariantDetail
和ProductVariant
。两个表中的映射ID是正确的。
但这会发生:
Products -> VariantDetails -> Variants = null
我试图通过以下方式缩短查询时间:
var xxx = db.ProductVariantDetails.Include(m => m.Variants).ToList();
正确加载了变体。因此,我确定嵌套的include或bug会存在问题。
这太奇怪了。因此,我尝试使用该代码。我把这个:
var xxx = db.ProductVariantDetails.Include(m => m.Variants.Select(z => z.VariantType)).ToList();
IQueryable<ManageProductItems> models = db.Products
.Include(m => m.Collections).Include(m => m.Images)
.Include(m => m.VariantDetails.Select(x => x.Variants.Select(z => z.VariantType)))
.Select....
因此,xxx
缓存了VariantType
,然后当models
查询整个实体时,Product -> VariantDetails -> Variants -> VariantType
被正确加载。如果我只查询models
而没有xxx
,则问题仍然存在。
因此,db
需要在此之前缓存Variants
和VariantTypes
。
我该如何解决?
答案 0 :(得分:0)
注意:这是第二个答案,它解决了代码中的第二个问题。首先阅读其他答案,因为我怀疑这将是您问题的最直接答案。
您的Select
正在撤消/忽略您的Include
。 Include
用于(显式)隐式自动获取相关实体,但是Select
明确要求提供其他返回值,该返回值将覆盖您设置的隐式包含规则。
一些展示其工作原理的示例:
var list = db.Products
.ToList();
这将返回未加载相关实体的产品列表。
var list = db.Products
.Include(m => m.ProductOwner)
.ToList();
这将返回同时加载了ProductOwner
属性的产品列表。
var list = db.Products
.Select(p => p.Name)
.ToList();
var list2 = db.Products
.Include(m => m.ProductOwner)
.Select(p => p.Name)
.ToList();
两个列表都是一个字符串列表(带有产品名称)。进行Include
无关紧要。
var list = db.Products
.Select(p => p.ProductOwner.Name)
.ToList();
var list2 = db.Products
.Include(m => m.ProductOwner)
.Select(p => p.ProductOwner.Name)
.ToList();
两个列表都是字符串列表(带有产品所有者名称)。进行Include
无关紧要。
这是需要注意的重要部分:您不需要Include
来获取相关ProductOwner
实体的名称。这是因为您的Select
语句明确要求EF提取相关实体数据,因此EF不需要Include
,因为它无论如何都不需要隐式加载相关实体。
对于任何Select
语句(包括那些仍在使用完整Product
实体的语句)都保持这种行为。意思是:
var list = db.Products
.Select(p => new { Product = p })
.ToList();
var list2 = db.Products
.Include(m => m.ProductOwner)
.Select(p => new { Product = p })
.ToList();
在两种情况下,您都将获得Product
实体而没有与之相关的ProductOwner
,因为EF会监听Select
并忽略其他有关要加载的数据(包括Include
)。
答案 1 :(得分:0)
您缺少一个包含项:
db.Products
.Include(m => m.Collections)
.Include(m => m.Images)
.Include(m => m.VariantDetails.Select(x => x.Variants.Select(z => z.VariantType)))
.Select(...);
您从未要求自己加载Variants
。未加载Variants
时,所有随后相关的实体都将被忽略。
请尝试以下操作:
db.Products
.Include(m => m.Collections)
.Include(m => m.Images)
.Include(m => m.VariantDetails.Select(x => x.Variants))
.Include(m => m.VariantDetails.Select(x => x.Variants.Select(z => z.VariantType)))
.Select(...);
但是,可能由于掩盖Select
语句而隐藏了第二个问题。我添加了第二个答案来解决这个潜在的次要问题。