[英]Complex LINQ 'Any' query
我有以下与实体框架对应的表:
发票(InvoiceID,InvoiceNumber,IsPaid)
零件(PartID,PartNumber,OrganizationID,IsActive)
发票_零件(发票ID,零件ID,数量,已声明)
我正在尝试从Invoices_Parts
表中获取具有多种条件的InvoiceID List
。 我遇到的问题是“其中Invoices_Parts
中的任何 Part
均处于活动状态”。
到目前为止的代码:
IQueryable<int> partIds = db.Parts.Where(x =>
x.OrganisationID == loggedInUser.OrganisationID).Select(y => y.PartID);
// && x.IsActive
List<string> invoiceIds = db.Invoices_Parts.Where(x =>
!x.IsClaimed && x.Invoice.IsPaid && partIds.Contains(x.PartID)
.DistinctBy(y => y.InvoiceID)
.Select(z => z.InvoiceID.ToString()).ToList();
我已经注释掉了“ && x.IsActive”,因为我希望InvoiceID的列表必须至少满足IsActive条件的一部分-我不想过滤掉IsActive为false的所有部分。 我如何在LINQ中实现此目标而又无需手动遍历集合和添加/删除项?
注意 :如果有人想知道,我将以下帮助方法用于DistinctBy
:
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
HashSet<TKey> seenKeys = new HashSet<TKey>();
foreach (TSource element in source)
{
if (seenKeys.Add(keySelector(element)))
{
yield return element;
}
}
}
编辑 :我对每个实体具有以下属性:
发票:
public virtual ICollection<Invoices_Parts> Invoices_Parts { get; set; }
部分:
public virtual ICollection<Invoices_Parts> Invoices_Parts { get; set; }
Invoices_Parts:
public virtual Invoice Invoice { get; set; }
public virtual Part Part { get; set; }
人们经常使LINQ查询变得过于复杂,因为它们习惯于从SQL表,联接等方面进行思考。 通常,如果您用朴素的英语表达您的实际需求,则可以提出一个更简单的查询,该查询的内容几乎完全相同。
我想要一张发票ID列表,该发票ID来自该发票上任何部分处于活动状态的已付款发票,等等。
这个怎么样:
from invoice in db.Invoices
where invoice.IsPaid
where invoice.Invoices_Parts.Any(ip => !ip.IsClaimed &&
ip.Part.IsActive &&
ip.OrganisationID == loggedInUser.OrganisationID)
select invoice.InvoiceId
或者,如果您更喜欢方法语法:
db.Invoices.Where(i => i.IsPaid)
.Where(i => i.Invoices_Parts.Any(ip => !ip.IsClaimed &&
ip.Part.IsActive &&
ip.OrganisationID == loggedInUser.OrganisationID)
.Select(i => i.InvoiceId)
.ToList();
PS-如果愿意,可以执行.ToString()
,但以我的经验,最好将ID设置为强类型。
PPS-您可以创建一个DistinctBy方法,该方法可以很好地与Entity Framework配合使用(不强制过早评估),如下所示:
public static IQueryable<TSource> DistinctBy<TSource, TKey>(this IQueryable<TSource> source, Excpression<Func<TSource, TKey>> keySelector) {
return source.GroupBy(keySelector).Select(i => i.FirstOrDefault());
}
好的,假设您希望所有发票中至少有一部分处于活动状态,那么我将这样做:
IQueryable<int> partIds = db.Parts
.Where(x => x.OrganisationID == loggedInUser.OrganisationID && x.IsActive)
.Select(y => y.PartID);
List<string> invoiceIds = db.Invoices_Parts
.Where(x => !x.IsClaimed && x.Invoice.IsPaid && partIds.Contains(x.PartID))
.Select(y => y.InvoiceID.ToString())
.Distinct()
.ToList();
如果那看起来很像您所拥有的,那是因为。 据我了解的问题,您的存在率已经达到99.99%。
您在这里可以做的是将发票与零件合并,以为每个发票创建所有零件的集合。 一旦有了该集合,确定其中是否有任何活动就很容易了:
List<string> invoiceIds =
(from invoice in db.Invoices_Parts
where !invoice.IsClaimed && invoice.Invoice.IsPaid
join part in partIds
on invoice.PartId equals part into parts
where parts.Any(part => part.IsActive)
select invoice.InvoiceID)
.Distinct()
.ToList();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.