2013-03-25 97 views
0

我有以下类的实体框架模型(我已经简化了类简单的观看):实体框架LEFT OUTER JOIN不工作

PuzzleItem 
-PuzzleId (int, primary key) 
-Title 

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

PuzzleItem我有多个层次。 PuzzleProgress通过在用户完成以前的级别时插入该级别的记录来跟踪用户处于哪个级别。一开始,新用户将在PuzzleProgressPuzzleId = 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不能为null,因为它必须具有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

感谢,其他的建议的工作为好,但我更喜欢你的方法,因为它更具有可读性给我! – 2013-03-26 07:16:14

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) 
      };