2013-03-25 3 views
0

У меня есть модель Entity Framework со следующими классами (я упростил классы для упрощения просмотра):Entity Framework левое внешнее соединение не работает

PuzzleItem 
-PuzzleId (int, primary key) 
-Title 

PuzzleProgress 
-ProgressId (int, primary key) 
-PuzzleId (FK) 
-UserId (FK) 

В PuzzleItem У меня есть несколько уровней. PuzzleProgress отслеживает, на каком уровне находится пользователь, вставляя запись этого уровня, когда пользователь завершает предыдущий уровень. Для начала новый пользователь будет иметь одну запись в PuzzleProgress с PuzzleId = 1.

В моем коде я использую следующую инструкцию для выполнения левого внешнего соединения, так что я получу список всех головоломок и укажу, какая головоломка не была решена. Я сделал ссылку на this post from StackOverflow.

Вот мой код:

var result = from pzs in e.PuzzleItems 
         join prg in e.PuzzleProgresses on pzs equals prg.PuzzleItem 
         into pzs_prg_tbl 
         from pzs_prg in pzs_prg_tbl.DefaultIfEmpty() 
         where pzs_prg.UserId == userId 
         select new SimplePuzzleItem() 
         { 
          PuzzleId = pzs_prg.PuzzleId, 
          PuzzleName = pzs_prg.PuzzleItem.Title, 
          IsUnlocked = (pzs_prg == null?false:true) 
         }; 

После запуска кода, только первый уровень этого нового пользователя возвращается (в то время как PuzzleItem таблица имеет 3 записи).

Я пробовал играть с кодом, но тот, который я наклеил выше, является ближайшим, к которому я могу добраться, может ли кто-нибудь указать мне правильное направление? Благодаря!

ответ

3

Это немного трудно точно сказать, не видя больше кода, но where pzs_prg.UserId == userId, вероятно, отрицая левое внешнее соединение.

Что я имею в виду, если вы планируете PuzzleItems LEFT JOIN PuzzleProgress, тогда вы хотите, чтобы все PuzzleItems, даже если нет PuzzleProgress. Но значение where pzs_prg.UserId == userId означает, что функция PuzzleProgress не может быть нулевой, поскольку она должна иметь значение UserId (значение userId). Таким образом, вы фактически имеете внутреннее соединение.

Лично мне не нравится «правильный» способ делать присоединяется (влево или внутренний) в LINQ, так это то, как я хотел бы исправить Linq заявление:

 var result = from pz in db.PuzzleItems 
        from pg in db.PuzzleProgresses 
            .Where(pg => pg.PuzzleId == pz.PuzzleId) 
            .Where(pg => pg.UserId == userId) 
            .DefaultIfEmpty() 
        select new 
           { 
            PuzzleId = pz.PuzzleId, 
            PuzzleName = pz.Title, 
            IsUnlocked = (pg != null) 
           }; 

Это читает намного больше подобно SQL-соединениям, которые я изучил давно, так что это соответствует моим соображениям.

Если вы хотите повторно профакторизовать присоединиться синтаксисом типа, смотреть на это 'LINQ Joining in c# with multiple conditions'

+0

Спасибо, другое предложение работало хорошо, но я бы предпочел свой подход, поскольку он является более удобным для чтения для меня! –

1

Я думаю, что предложение where отфильтровывает записи. Вам нужно включить предложение where в ваше левое соединение. Как так:

var result = from pzs in e.PuzzleItems 
      join prg in e.PuzzleProgresses on new { pzs.PuzzleId, UserId = userId } equals new { prg.PuzzleId, prg.UserId } 
      into pzs_prg_tbl 
      from pzs_prg in pzs_prg_tbl.DefaultIfEmpty() 
      select new SimplePuzzleItem() 
      { 
       PuzzleId = pzs_prg.PuzzleId, 
       PuzzleName = pzs_prg.PuzzleItem.Title, 
       IsUnlocked = (pzs_prg == null?false:true) 
      }; 
Смежные вопросы