2013-02-25 2 views
2

Привет Я кодирую свой путь в примерах MS 101 linq.Linq SelectMany

«JoinOperators» мне очень тяжело, так как я пытаюсь реорганизовать выражения запросов на синтаксис лямбда и наоборот.

Во всяком случае, на примере 105 я вижу это выражение запроса:

var supplierCusts = 
    from sup in suppliers 
    join cust in customers on sup.Country equals cust.Country into cs 
    from c in cs.DefaultIfEmpty() // DefaultIfEmpty preserves left-hand elements that have no matches on the right side 
    orderby sup.SupplierName 
    select new 
    { 
     Country = sup.Country, 
     CompanyName = c == null ? "(No customers)" : c.CompanyName, 
     SupplierName = sup.SupplierName 
    }; 

И я попытался его реализации как лямбда так:

// something is not right here because the result keeps a lot of "Join By" stuff in the output below 
var supplierCusts = 
    suppliers.GroupJoin(customers, s => s.Country, c => c.Country, (s, c) => new { Customers = customers, Suppliers = suppliers }) 
     .OrderBy(i => i.Suppliers) // can't reference the "name" field here? 
     .SelectMany(x => x.Customers.DefaultIfEmpty(), (x, p) => // does the DefaultIfEmpty go here? 
      new 
      { 
       Country = p.Country, 
       CompanyName = x == null ? "(No customers)" : p.CompanyName, 
       SupplierName = p // not right: JoinOperators.Program+Customer ... how do I get to supplier level? 
      }); 

По какой-то причине я не могу получить доступ к поставщику -уровень информации таким образом. Когда я выключаю клиентов с поставщиками, я не могу получить доступ к информации на уровне клиента.

Есть ли какая-то перегрузка SelectMany, которая позволяет мне тянуть с уровня поля обоих объектов?

Кроме того, я не понимаю, почему GroupJoin, кажется, возвращает объект с двумя коллекциями (поставщиками и клиентами). Разве это не должно так или иначе присоединиться к ним?

Думаю, я не понимаю, как работает GroupJoin.

ответ

5

Вы неправильно селектор результата в группе присоединиться, что там начались проблемы. Здесь фиксируется запрос:

var supplierCusts = 
    suppliers 
    .GroupJoin(customers, 
       sup => sup.Country, 
       cust => cust.Country, 
       (sup, cs) => new { sup, cs }) 
    .OrderBy(x => x.sup.Name)  
    .SelectMany(x => x.cs.DefaultIfEmpty(), (x, c) => 
     new 
     { 
      Country = x.sup.Country, 
      CompanyName = c == null ? "(No customers)" : c.CompanyName, 
      SupplierName = x.sup.Name 
     }); 
+0

Каждый раз, когда я пытаюсь запрос, как это, я получаю сообщение об ошибке, «Операция„GroupJoin“должна сопровождаться операцией,„SelectMany“, где селектор коллекции ссылающегося на„DefaultIfEmpty“ метод «. Что с этим? – Boydski

+0

@ Бойдски никогда не сталкивался с этой ошибкой раньше. Можете ли вы опубликовать свою проблему как вопрос с шагами по воспроизведению? –

+0

http://stackoverflow.com/questions/20336653/outer-join-with-linq-causing-groupjoin-error – Boydski

1

Если вы хотите изучить перевод выражений запроса в лямбда, я предлагаю вам проверить LinqPad, который может это сделать по умолчанию. Например, запрос переводится следующим образом:

Suppliers 
    .GroupJoin (
     Customers, 
     sup => sup.Country, 
     cust => cust.Country, 
     (sup, cs) => 
     new 
     { 
      sup = sup, 
      cs = cs 
     } 
    ) 
    .SelectMany (
     temp0 => temp0.cs.DefaultIfEmpty(), 
     (temp0, c) => 
     new 
     { 
      temp0 = temp0, 
      c = c 
     } 
    ) 
    .OrderBy (temp1 => temp1.temp0.sup.CompanyName) 
    .Select (
     temp1 => 
     new 
     { 
      Country = temp1.temp0.sup.Country, 
      CompanyName = (temp1.c == null) ? "(No customers)" : temp1.c.CompanyName, 
      SupplierName = temp1.temp0.sup.CompanyName 
     } 
    ) 

Это, как говорится, я обычно найти SelectMany быть проще кодировать и поддерживать с помощью синтаксиса запросов вместо синтаксиса лямбда.

В этом примере GroupJoin используется для выполнения левого соединения (через предложение .DefaultIfEmpty).

1

Попробуйте это:

var supplierCusts = 
    suppliers.GroupJoin(customers, s => s.Country, c => c.Country, (s, c) => new { Supplier = s, Customers = c }) 
     .OrderBy(i => i.Supplier.SupplierName) 
     .SelectMany(r => r.Customers.DefaultIfEmpty(), (r, c) => new 
     { 
      Country = r.Supplier.Country, 
      CompanyName = c == null ? "(No customers)" : c.CompanyName, 
      SupplierName = r.Supplier.SupplierName 
     }); 
Смежные вопросы