我想选择所有Site_Report
项,其中Asset_Calcert
至少有一个条件为Asset_Calcert.Cert_type == 3
的项。关系为1-0 .. *,如下所示。
如果要对多个实体设置条件,我该如何处理,就我而言,我想对父级和子级都设置条件。即Site_report.report_status == 2
和Asset_Calcert.Cert_type == 3
我已经尝试过以下方法,但是这样做不正确,因为这种方法会出错。
IEnumerable<Site_Report> model;
using (var ctx = new ApplicationDbContext())
{
model = ctx.Site_Report.Include(i => i.Published_By)
.Include(i => i.Handled_By)
.Include(i => i.Report_Assets.Select(c => c.Asset_Calcerts))
.Where(report => report.report_status == DBConstant.REPORT_STATUS_CONCLUDED)
// Error ------> // .Where(rp => rp.Report_Assets.Where(c => c.Asset_Calcerts.Any(d => d.cert_type == 3)))
.OrderByDescending(o => o.publish_date);
}
错误
无法将类型'System.collection.Generic .IEnumerable'隐式转换为'bool'。
错误CS1662无法将lambda表达式转换为预期的委托类型,因为该块中的某些返回类型不能隐式转换为委托返回类型
模式仅为简洁起见添加必要的字段
public class Site_Report
{
public int site_report_id { get; set; }
public int report_status { get; set; }
// Navigation Properties
public virtual ICollection<Report_Asset> Report_Assets { get; set; }
public Site_Report()
{
this.Report_Assets = new HashSet<Report_Asset>();
}
}
public class Report_Asset
{
public int report_asset_id { get; set; }
// Navigation Properties
public int site_report_id { get; set; }
public virtual Site_Report Site_Report { get; set;
public Report_Asset()
{
this.Asset_Calcerts = new HashSet<Asset_Calcert>();
}
}
public class Asset_Calcert
{
public int asset_calcert_id { get; set; }
public int cert_type { get; set; }
// Navigation Properties
public int report_asset_id { get; set; }
public virtual Report_Asset Report_Asset { get; set; }
}
答案 0 :(得分:0)
Queryable.Where
使用谓词参数。谓词通常以以下格式编写:
report => Some expression that takes report as input, and a Boolean as output
您的谓词是:
rp => rp.Report_Assets.Where(c => c.Asset_Calcerts.Any(d => d.cert_type == 3))
所以您的表情是:
rp.Report_Assets.Where(c => c.Asset_Calcerts.Any(d => d.cert_type == 3))
此表达式的值不是布尔值,而是IQueryable<ReportAssert>
!当您将鼠标悬停在Visual Studio上时,Visual Studio肯定会告诉您吗?
您写道:我想选择所有Site_Report条目,其中Asset_Calcert至少有一个条件为Asset_Calcert.Cert_type == 3
或者稍微重新措辞:
要求:我希望所有具有至少一个ReportAsset且至少具有一个AssetCalCert且其中AssetCalCert.CertType等于3的ReportAsset的所有SiteReports的所有(或某些)属性
如果要选择“序列中的序列”的属性,请使用SelectMany而不是Select:
var result = myDbContext.SiteReports
.Where(siteReport => siteReport.ReportAssets.SelectMany(reportAsset => reportAsset.AssetCalCerts)
// I only want this siteReport if at least one of the AssertCalCerts
// has a certType value equal to 3
.Any(assertCalCert => assertCalCert.CertType == 3))
// from the resulting SiteReports selecte the properties that you plan to use:
.Select(siteReport => new
{
Id = siteReport.Id,
Name = siteReport.Name,
...
ReportAsserts = siteReport.ReportAssets.Select(reportAsset => new
{
Id = reportAssert.Id,
...
AssetCalCerts = reportAsset.AssetCalCerts.Select(assetCalCert => new
{
...
})
.ToList(),
})
.ToList(),
};
查询数据时,请始终使用“选择”,并仅选择计划使用的属性。仅在计划更新获取的项目时才使用“包括”。
如果SiteReport [10]具有1000个ReportAsset,则每个ReportAsset都将具有一个值为10的SiteReport外键。将相同的值传输10超过1000次将是浪费的。
请注意,我使用了匿名类型:
siteReport => new
{
...
}
我当然可以使用new SiteReport()
来代替。但是,如果我使用了该变量,那我将传输几个我不打算使用的变量。当然,我可以跳过填充不使用的属性,但是如果我的读者得到一个SiteReport
对象,他们可能会期望所有值都被填充。
因此,尽管使用匿名类型更为有效,但缺点是您不能将匿名类型用作返回值。如果需要这样做,最好的方法是将代表数据库表的类与代表获取的数据的类分开:(适配器设计模式?还是门面?)
class AdaptedSiteReport()
{
... only properties that queriers plan to use
}
在LINQ语句中
siteReport => new AdaptedSiteReport() {...}
将实际数据库与获取的表示形式分离的优点是,您可以更改内部数据库表示形式,而无需用户注意。