【问题标题】:Entity Framework left outer join not working实体框架左外连接不起作用
【发布时间】:2013-03-15 06:26:55
【问题描述】:

我有一个包含以下类的实体框架模型(我已经简化了这些类以便于查看):

 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条记录)。

我尝试过使用代码,但我上面粘贴的代码是我能到达的最近的代码,有人能指出我正确的方向吗?谢谢!

【问题讨论】:

    标签: wcf entity-framework


    【解决方案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)
                 };
    

    【讨论】:

      【解决方案2】:

      如果不看更多代码,很难说清楚,但where pzs_prg.UserId == userId 可能会否定左外连接。

      我的意思是,如果您打算使用PuzzleItems LEFT JOIN PuzzleProgress,那么即使没有 PuzzleProgress,您也需要所有 PuzzleItems。但是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'

      【讨论】:

      • 谢谢,另一个建议也很有效,但我更喜欢你的方法,因为它对我来说更具可读性!
      猜你喜欢
      • 1970-01-01
      • 2011-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-18
      • 1970-01-01
      • 1970-01-01
      • 2013-05-18
      相关资源
      最近更新 更多