我有一个包含以下类的实体框架模型(我已经简化了类以便更简单地查看):
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条记录)。
我尝试过使用代码,但我粘贴的代码是我能找到的最近的代码,有人能指出正确的方向吗?谢谢!
答案 0 :(得分:3)
如果没有看到更多的代码,说起来有点难,但where pzs_prg.UserId == userId
可能会否定左外连接。
我的意思是,如果您打算PuzzleItems LEFT JOIN PuzzleProgress
,那么即使没有PuzzleProgress,您也想要所有PuzzleItems。但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'
答案 1 :(得分: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)
};