复杂的LINQ“任何”查询

我有以下表与entity framework映射:

发票(InvoiceID,InvoiceNumber,IsPaid)
零件(PartID,PartNumber,OrganisationID,IsActive)
Invoices_Parts(InvoiceID,PartID,Quantity,IsClaimed)

我正在尝试从Invoices_Parts表中获取具有许多条件的InvoiceID List 。 我遇到问题的条件是“ Invoices_Parts中的任何 Part处于活动状态”。

到目前为止的代码:

 IQueryable partIds = db.Parts.Where(x => x.OrganisationID == loggedInUser.OrganisationID).Select(y => y.PartID); // && x.IsActive List 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中实现此function而无需手动循环收集和添加/删除项目?

注意 :如果有人想知道,我正在使用DistinctBy的以下帮助方法:

 public static IEnumerable DistinctBy(this IEnumerable source, Func keySelector) { HashSet seenKeys = new HashSet(); foreach (TSource element in source) { if (seenKeys.Add(keySelector(element))) { yield return element; } } } 

编辑 :我在每个实体上都有以下属性:

发票:

 public virtual ICollection Invoices_Parts { get; set; } 

部分:

 public virtual ICollection Invoices_Parts { get; set; } 

Invoices_Parts:

 public virtual Invoice Invoice { get; set; } public virtual Part Part { get; set; } 

人们经常使LINQ查询过于复杂,因为他们习惯于在SQL表,连接等方面进行思考。 通常,如果您将实际需求放在简​​单的英语中,您可以提出一个更简单的查询,它几乎完全相同。

我想要一张付款发票中的发票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 – 您可以创建一个与Entity Framework完美匹配的DistinctBy方法(不强制过早评估),如下所示:

 public static IQueryable DistinctBy(this IQueryable source, Excpression> keySelector) { return source.GroupBy(keySelector).Select(i => i.FirstOrDefault()); } 

好的,假设您想要至少有一部分ON THAT INVOICE处于活动状态的所有发票,我会这样做:

 IQueryable partIds = db.Parts .Where(x => x.OrganisationID == loggedInUser.OrganisationID && x.IsActive) .Select(y => y.PartID); List 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 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();