2015-04-22 4 views
1

Я пытаюсь преобразовать следующий SQL:C# Lambda Соединение слева - не может заставить его работать

select * from business 
left outer join permissions on permissions.permid = busid 
and anotherid = 17 

в лямбда-выражения C#, а затем преобразовать его в перечислимого и сделать еще один фильтр на нем. Я пробовал следующий код:

 IEnumerable<DTO_business> business= db.business 
      .Join(db.permissions, 
       bus => bus.busid, 
       perm => perm.perm_busid,     
       (bus, perm) => new { bus, perm }) 
      .Where(e => e.perm.anotherid == 17).DefaultIfEmpty() 
      .AsEnumerable() 
      .Where(User.IsInRole("Administrator") 
      .Select(bus => 
          new DTO_business() 
               { 
                BusinessID = bus.bus.busid.Convert(), 
                BusinessName = bus.bus.busname.Convert() 
               }); 

Но я верю, что он не работает как место, находящееся за пределами соединения. Я не уверен, как на самом деле получить это, где в рамках соединения, а затем запустить DefaultIfEmpty() в соединении, которое должно дать мне левое соединение.

EDIT: бит, который я не могу получить, это: и anotherid = 17. Если я помещу его в. Где в linq он полностью фильтрует его и не является частью левого соединения.

ответ

1

Для меня предложение LINQ join всегда прост с синтаксисом запроса. Если вы предпочитаете, это то, как вы можете сделать: -

var result = from permission in db.permissions 
      join business in db.business 
      on permission.permid equals business.busid into b 
      from bus in b.DefaultIfEmpty() 
      where permission.anotherid == 17 
      select new DTO_business() 
          { 
           BusinessID = bus != null ? bus.busid : 0, 
           BusinessName = bus != null ? bus.busname : String.Empty 
          }; 
+0

Не уверен, что могу использовать синтаксис запроса, поскольку мне нужно преобразовать в перечислимый (получить результаты в памяти), поскольку я выполняю функции C# (не SQL) для каждого возвращаемого элемента. – user3129594

+0

@ user3129594 - Синтаксис запроса в конечном итоге преобразуется в лямбда и производит тот же вывод. Я не вижу причин, по которым вы не можете использовать синтаксис запроса здесь. –

+0

Да, но для этого мне не нужно создавать другой DTO (который принимает все результаты из шины и разрешений), а затем превращать iqueryable в ienumeral, а затем делать преобразования в методе? Или я чего-то не хватает? – user3129594

1

Синтаксис запросов будет легче IMHO, но вы можете сделать это с помощью GroupJoin так:

var business= db.business 
        .GroupJoin(
         db.permissions, 
         bus => bus.busid, 
         perm => perm.perm_busid,     
         (bus, perm) => new { bus, perm }) 
        .SelectMany(
         z => z.permissions.DefaultIfEmpty(), 
         (x, y) => new { Business = x.Bus, Permission = y }) 
        .Where(z => z.Permission.anotherid == 17) 
        .Select(s => new DTO_business 
        { 
         BusinessID = s.Business.busid.Convert(), 
         BusinessName = s.Business.busname.Convert() 
        }); 

Reference: LEFT OUTER JOIN in LINQ

+0

Спасибо за быстрый ответ! Проблема заключается в том, что он все еще выполняет WHERE, который отфильтровывает все результаты. Фильтр должен находиться в LEFT OUTER JOIN, поэтому, если правильная таблица (разрешения) ничего не возвращает, левая таблица (бизнес) все еще отображается. Использование где по-прежнему фильтрует все результаты :-( – user3129594

+0

Логически, если бы я мог поместить .Where выше SelectMany, это должно работать (так как это сделает фильтр, который устранит строки разрешений, но затем SelectMany вернет их с null. Проблема с этим заключается в том, что Where выше SelectMany не позволяет мне фильтровать по perm! – user3129594

0

Вы можете использовать составной ключ в условии соединения.

  from p in db.permissions 
     join b in db.business 
     on new { BusId = b.busid, AnotherId= b.anotherId} 
     equals new { BusId = p.perm_busid, AnotherId = 17 } into all 
     from b in all.DefaultIfEmpty()    
     select new DTO_business 
       { 
        BusinessID = b.busid, // check for null reference 
        BusinessName = b.busname // check for null reference 
       }; 

Вы также можете использовать составные клавиши аналогично в синтаксисе расширения.

В вашем коде вы видите Convert в функции выбора. Это не допускается в Linq, который преобразуется в Sql.

Смежные вопросы