2017-08-03 111 views
1

我试图找到买方的所有发票,通过买方名称搜索(包含和等于过滤器)。寻找最干净的方式来做到这一点。 我有一个买家名单。C#LINQ。按对象名称属性或名称部分搜索对象

List <Buyer> AllBuyers; 

,买受人为:

public class Buyer 
    { 
     public string BuyerIdentifier{ get; set; } 
     public string Name { get; set; } 
    } 

我有发票的买家名单。

List <Invoice> AllInvoices; 

而且发票是

public class Invoice 
    { 
     public string InvoiceID { get; set; } 
     public string BuyerID { get; set; } 
     public string Amount{ get; set; } 
    } 

我目前在做什么:

List<string> BuyerIDs = new List<string> { }; 
foreach (Invoice inv in AllInvoices) 
{ 
    if (!(BuyerIDs.Contains(inv.BuyerID))) 
    { 
     // add BuyerID to list if it's not already there. Getting id's that are present on invoices and whose Buyer names match using contains or equals 
     BuyerIDs.Add(AllBuyers.First(b => b.BuyerIdentifier == inv.BuyerID 
      && (b.Name.IndexOf(SearchValue, StringComparison.OrdinalIgnoreCase) >= 0)).BuyerIdentifier); 
    }             
} 
Invoices = AllInvoices.FindAll(i=> BuyerIDs.Contains(i.BuyerID)); 

LINQ查询语法有点容易,我比LINQ方法加入明白。所以经过下面我的答复我现在这样做:

Invoices = (from buyer in AllBuyers 
       join invoice in AllInvoices on buyer.BuyerIdentifier equals invoice.BuyerID 
       where buyer.Name.IndexOf(SearchValue, StringComparison.OrdinalIgnoreCase) >= 0         
       select invoice).ToList(); 
+2

请问你的代码的工作?如果确实如此,并且您只是希望改进代码,则此问题可能属于[Code Review Stack Exchange](https://codereview.stackexchange.com/),而不是此处。否则,你有什么问题,或者你看到了什么错误? –

+0

它的工作原理,我只是想知道是否有一个更好的方式在LINQ做到没有foreach循环,如果条件。 – Razkar

+0

我不知道你在做什么,但你可能只是做一个加入 –

回答

1

这里就是我创建BuyerIdentifier字典作为键和值发票列表的建议:

var dict = AllBuyers.ToDictionary(k => k.BuyerIdentifier, 
       v => AllInvoices.Where(i => i.BuyerID == v.BuyerIdentifier).ToList()); 

然后你就可以访问像这样一个特定买方发票清单:

List<Invoice> buyerInvoices = dict[buyerId]; 
+3

这是非常低效的。 – Iucounu

0

这应该为你工作:

var InvoiceGrouping = AllInvoices.GroupBy(invoice => invoice.BuyerID) 
           .Where(grouping => AllBuyers.Any(buyer => buyer.BuyerIdentifier == grouping.Key && buyer.Name.IndexOf(pair.Value, StringComparison.OrdinalIgnoreCase) >= 0)); 

您最终得到的是一个以买方ID为关键字和所有发票作为值的分组。在其结束,因为IGrouping工具IEnumerable,展平了分组到单一的价值枚举

var Invoices = AllInvoices.GroupBy(invoice => invoice.BuyerID) 
          .Where(grouping => AllBuyers.Any(buyer => buyer.BuyerIdentifier == grouping.Key && buyer.Name.IndexOf(pair.Value, StringComparison.OrdinalIgnoreCase) >= 0)) 
          .SelectMany(grouping => grouping); 

注意添加SelectMany

如果你想要发票的只是一个平面列表,你可以像这样。

2

如果你需要的是发票,您可以加入你的两个集合,过滤器,并选择发票

AllBuyers.Join(AllInvoices, 
      a => a.BuyerIdentifier, 
      a => a.BuyerID, 
      (b, i) => new { Buyer = b, Invoice = i }) 
    .Where(a => a.Buyer.Name.Contains("name")) 
    .Select(a => a.Invoice).ToList(); 

如果你想购房者为好,只是离开了.Select(a => a.Invoice)。 字符串的Contains方法也会匹配equals。

+0

谢谢,我想加入是我正在寻找。至于Contains,我希望不区分大小写的搜索,并且不想使用toLower()。 – Razkar

+1

我认为在执行加入之前,您可以从买家过滤中受益。我想这是OP最后一次编辑后的意图。也就是说,他打算通过名称上的搜索值筛选买家(这可能会大大减少买家的完整列表) –

+0

只需要一次加入警告,如果您无法保证每名买家只有一次在列表中,您会在结果中获得重复的发票。 –

0

作为ILookup变形金刚迷,这将是我的做法:

var buyerMap = AllBuyers 
    .Where(b => b.Name.IndexOf(SearchValue, StringComparison.OrdinalIgnoreCase) >= 0) 
    .ToDictionary(b => b.BuyerIdentifier); 

var invoiceLookup = AllInvoices 
    .Where(i => buyerMap.ContainsKey(i.BuyerID)) 
    .ToLookup(x => x.BuyerID); 

foreach (var invoiceGroup in invoiceLookup) 
{ 
    var buyerId = invoiceGroup.Key; 
    var buyer = buyerMap[buyerId]; 
    var invoicesForBuyer = invoiceGroup.ToList(); 

    // Do your stuff with buyer and invoicesForBuyer 
} 
+0

其实,你不需要查询,'GroupBy'就够了,可能更干净 –