LINQ查询帮助

时间:2011-06-22 12:08:10

标签: c# .net linq linq-to-sql linq-to-objects

我有这个查询,它在Books,TradingDesks和ProductInfos上运行连接。每个集合中的数据都很庞大。

var queryJoin = from b in books.Values
                                    join d in tradingDesks.Values
                                        on b.TradingDeskId equals d.Id
                                    join p in ProductInfos.Values
                                        **on b.Id equals p.RiskBookId** 
                                    select new { p, Book = b.Name, TradingDeskName = d.Name };

在突出显示的行(on b.Id equals p.RiskBookId)中,我还想添加其他条件,例如(on b.Id equals p.RiskBookId || p.RiskBookId == 0)。我如何在这个linq语法中执行此操作。

我试过像这样查询

var queryJoin = from b in books.Values
                from d in tradingDesks.Values.Where(x => x.Id == b.TradingDeskId)
                from p in cachedProductInfos.Values.Where(y => y.RiskBookId == b.Id)
                select new { p, Book = b.Name, TradingDeskName = d.Name };

但在这种情况下,查询会永远运行,而且内存不足。所以我想以这种方式构建它会让人感到疯狂:(

感谢任何帮助。

由于 摩尼

5 个答案:

答案 0 :(得分:2)

在原始查询中,对Enumerable.Join的调用正在幕后使用哈希表来快速创建。如果切换到.Where,则不会获得这些哈希优势。您可以显式使用散列来获得相同的效果。

ILookup<int, string> deskNameLookup = tradingDesks.Values
  .ToLookup(
    d => d.Id,
    d => d.Name
  );

ILookup<int, ProductInfo> infoLookup = ProductInfos.Values
  .ToLookup(p.RiskBookId);

foreach(b in books.Values)
{
  foreach(dName in deskNameLookup[b.TradingDeskId])
  {
    foreach(p in infoLookup[b.Id].Concat(infoLookup[0]))
    {
      var x = new {p, Book = b.Name, TradingDeskName = dName};
    }
  }
}

答案 1 :(得分:1)

您可以尝试将其框架化为联合而不是单个联接:

var baseQuery = 
    from book in books.Values
    join desk in tradingDesks.Values on book.TradingDeskId equals desk.Id
    select new {book, desk};

var conditionOne = 
    from baseQ in baseQuery
    join productInfo in ProductInfos.Values on baseQ.book.Id equals productInfo.RiskBookId
    select new 
    { 
        productInfo, 
        Book = baseQ.book.Name, 
        TradingDeskName = baseQ.desk.Name
    };

var conditionTwo = 
    from baseQ in baseQuery
    join productInfo in ProductInfos.Values on book.Id equals 0
    select new 
    {
        productInfo, 
        Book = baseQ.book.Name, 
        TradingDeskName = baseQ.desk.Name
    };

var result = conditionOne.Union(conditionTwo);

答案 2 :(得分:0)

equals只能用于进行单一比较。

其他人可能能够针对您的情况为您提供优化的查询方法,但添加到equals条件不是此处的解决方案。可能最好的方法是以不同的方式处理它 - 而不是通过某种定制的加载和缓存机制来处理单个查询体内的所有数据 - 因为数据的大小显然是有问题的。

答案 3 :(得分:0)

尝试这一点,一点点逐字,但应该像你描述的那样工作:

var queryJoin =
    from b in books.Values
    join d in tradingDesks.Values on b.TradingDeskId equals d.Id
    let p =
        from pi in ProductInfos.Values
        where (b.Id == pi.RiskBookId) || (pi.RiskBookId == 0)
        select pi
    where p.Any()
    select new
    {
        p,
        Book = b.Name,
        TradingDeskName = d.Name
    };

答案 4 :(得分:-1)

实际上:

join d in tradingDesks.Values
    on (b.Id equals p.RiskBookId || p.RiskBookId equals 0)

on (b.Id == p.RiskBookId || p.RiskBookId == 0)

应该完美无缺。

联接需要一个真实的条件:

on <expression>

(b.Id equals p.RiskBookId || p.RiskBookId == 0) 

将返回true或false,因此连接应该对此进行评估。