Справка по LINQ Query - PullRequest
2 голосов
/ 22 июня 2011

У меня есть этот запрос, который запускает объединение в 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 };

Но в этом случае запрос выполняется вечно, и мне не хватает памяти. Поэтому я думаю, что создание этого способа делает что-то сумасшедшее: (

Любая помощь приветствуется.

Спасибо Mani

Ответы [ 5 ]

2 голосов
/ 22 июня 2011

В исходном запросе эти вызовы 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 голос
/ 23 июня 2011

Вы можете попробовать создать его как объединение вместо одного соединения:

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);
0 голосов
/ 22 июня 2011

equals можно использовать только для одного сравнения.

Кто-то может предложить вам оптимизированный подход к запросу с учетом ваших обстоятельств, но добавление к условию equals здесь не является решением. Однако лучше всего подойти к нему по-другому - вместо того, чтобы извлекать все данные из тела одного запроса - с помощью какого-то специального механизма загрузки и кэширования, поскольку размер данных явно проблематичен.

0 голосов
/ 22 июня 2011

попробуйте это, немного дословно, но должно работать так, как вы это описали:

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
    };
0 голосов
/ 22 июня 2011

На самом деле:

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, поэтому объединение ДОЛЖНО оценить это именно так.

...