【发布时间】:2014-02-23 05:00:24
【问题描述】:
我用实体框架映射了以下表格:
发票(InvoiceID、InvoiceNumber、IsPaid)
部件(PartID、PartNumber、OrganisationID、IsActive)
Invoices_Parts(InvoiceID、PartID、Quantity、IsClaimed)
我正在尝试从具有多个条件的 Invoices_Parts 表中获取 List 的 InvoiceID。我遇到问题的条件是“Invoices_Parts 中的 any 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 为假的部分.如何在 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; }
【问题讨论】:
-
您的实体中有一些导航属性吗?
-
您可能知道这一点,但我应该指出,当您的 IQueryable 到达您的
DistinctBy扩展中的foreach时,它会触发。我想说,为了清楚起见,您应该在链中的DistinctBy()调用之前放置一个ToList(),以明确这是查询评估的位置。 -
@GeorgeMauer 添加
ToList不必要地立即评估整个查询,强制评估整个结果集,并具有创建/填充将被完全忽略的列表的开销。AsEnumerable无需任何额外开销即可实现所需的可读性语义。 -
实际上,在我看来,如果你把
IsActive测试放回去,你就会得到你想要的。您正在寻找InvoiceID值,因此将InvoiceID从所有Invoice_Parts记录中拉出,其中IsActive为真,其他情况为真,您应该会得到正确的结果。 -
是的,除了
DistinctBy扩展将已经强制触发查询。我特别反对的是它看起来不会(因为Distinct()是在LINQ 提供程序中实现的),但它实际上会(因为DistinctBy不是)。所以我想也许更好的建议是将其重命名为EvaluateAndDistinctBy
标签: c# linq entity-framework