我有三个表Site_Report
Report_Asset
和Asset_Calcert
,它们之间具有一对多的关系。
我想将子实体作为模型加载,即Report_Asset
,其中应包含某些父实体的属性。而且,我想从孙子的集合导航属性中,使用条件加载单个记录。
第一次尝试-这会导致错误。
Report_Asset model;
model = ctx.Report_Asset
.Include(i => i.Site_Report)
.Include(i => i.Site_Report.Handled_By)
.Include(i => i.Site_Report.Published_By)
.Include(i => i.Asset_Calcerts.Select(b => b.asset_calcert_id == assetCalcertId))
.FirstOrDefault();
错误:“包含”路径表达式必须引用在类型上定义的导航属性。使用虚线路径作为参考导航属性,使用“选择”运算符作为集合导航属性。
第二次尝试-通过启动子孙实体并包括其父母。这种方法确实加载了结果集,但它仅包含子实体,即Report_Asset
,没有来自Asset_Calcert
集合的记录,而对于Site_Report
则为null。
Report_Asset model;
model = ctx.Asset_Calcert.Include(i => i.Report_Asset)
.Include(i => i.Report_Asset.Site_Report.Handled_By)
.Include(i => i.Report_Asset.Site_Report.Published_By)
.Where(i => i.asset_calcert_id == assetCalcertId)
.Select(i => i.Report_Asset).FirstOrDefault();
我已经在DbContext()中设置了Configuration.LazyLoadingEnabled = false
。
需要指导,谢谢
答案 0 :(得分:2)
您似乎想查询并返回一个实体,它是父级,然后是子级的子集。您可以使用EF进行查询,但是只能将查询简化为所需的结构。如果返回Report_Asset,它可以很容易地包含对其父项的引用,但是它将始终引用其完整的子集,EF不会在实体级别过滤子集。
最好准确地查看每个实体想要的字段,并选择仅包含这些字段的结构,但是从最基本的角度来看,这应该可以为您提供所需的内容:
var model = ctx.Report_Asset
.Select( x = > new
{
Report_Asset = x,
Site_Report = x.Site_Report,
Handled_By = x.Site_Report.Handled_By,
Published_By = x.Site_Report.Published_By,
Asset_Calcerts = x.Assert_Calcerts.Where(c => c.asset_calcert_id == assetCalcertId).ToList()
}).FirstOrDefault();
calcert检查似乎是在寻找特定的单一证书,因此这样做可能更好:
var model = ctx.Report_Asset
.Select( x = > new
{
Report_Asset = x,
Site_Report = x.Site_Report,
Handled_By = x.Site_Report.Handled_By,
Published_By = x.Site_Report.Published_By,
Asset_Calcert = x.Assert_Calcerts.SingleOrDefailt(c => c.asset_calcert_id == assetCalcertId)
}).FirstOrDefault();
如果您希望仅加载具有匹配Calcert的报表资产,并同时包含父级和适用的calcert:
var model = ctx.Report_Asset
.Where(x => x.Asset_Calcerts.Any(c => c.asset_calcert_id == assetCalcertId))
.Select( x = > new
{
Report_Asset = x,
Site_Report = x.Site_Report,
Handled_By = x.Site_Report.Handled_By,
Published_By = x.Site_Report.Published_By,
Asset_Calcert = x.Asset_Calcerts.SingleOrDefailt(c => c.asset_calcert_id == assetCalcertId)
}).FirstOrDefault();
在所有情况下,我建议在OrderBy
之前添加一个FirstOrDefault
子句,以确保使用可预测的顺序。
此方法的警告是,如果您访问返回的模型的实体并开始向下钻取它们的引用,则仍然会触发数据库中的延迟加载。例如,如果我使用:
model.Report_Asset.Asset_Calcerts
仍然会延迟加载该报告资产的相关实体,并列出该资产的所有证书。过滤后的集合/匹配项会急切加载到模型中。Asset_Calcert(而不是返回的Model_Asset实体)。
通常,尽管最好使用Select
从各种实体中检索您关心的属性,而不是尝试选择整个实体或实体图。这就不需要使用Include
了,只需将实体图中的确切信息告诉EF,它将构建一条SQL语句来有效地检索该信息。
答案 1 :(得分:0)
当使用大于1的级别时,最好使用字符串选项。 如果您不想使用字符串,则需要选择大于1的级别。
Report_Asset model;
model = ctx.Report_Asset
.Include("Site_Report")
.Include("Site_Report.Handled_By")
.Include("Site_Report.Published_By")
.Include("Asset_Calcerts")
.FirstOrDefault(x => x.Asset_Calcerts.Any(y => y.asset_calcert_id == assetCalcertId);