我有一个私人消息表和一个用户表。
我在这里连接它们:
var messageUsers = (from pm in dc.PrivateMessages
join user in dc.Users
on pm.SenderID equals user.UserID
where !pm.IsDeletedRecipient && pm.RecipientID == id
select new PMInbox
{
SenderUsername = user.Username,
PrivateMessageID = pm.PrivateMessageID,
SenderID = pm.SenderID,
Subject = pm.Subject,
Text = pm.Text,
SenderType = pm.SenderType,
IsDeletedRecipient = pm.IsDeletedRecipient,
IsDeletedSender = pm.IsDeletedSender,
IsRead = pm.IsRead,
Timestamp = pm.TimestampSend
}).ToList();
如何在左连接中进行此操作,因此如果userID不是SenderID(例如,已完全删除发件人),则用户名应为空?
答案 0 :(得分:4)
var messageUsers = (
from pm in dc.PrivateMessages
where !pm.IsDeletedRecipient && pm.RecipientID == id
select new PMInbox {
SenderUsername = (
from user in dc.Users
where user.UserID == pm.SenderID
select user.Username
).SingleOrDefault(),
PrivateMessageID = pm.PrivateMessageID,
//...
}
).ToList();
通常,要在LINQ中实现Left外连接,当您希望包含连接的“table”的1或0行时,应该使用SingleOrDefault
或FirstOrDefault
,并{{ 1}}当你可能需要包含几个行时(根据我的经验,这是一个不太常见的场合)。在您的具体情况下,DefaultIfEmpty
听起来像是UserID
的唯一标识符 - 因此,我将您的左联接转换为Users
来电,而不是SingleOrDefault
来电。
与SQL不同,.NET无法解析空值的属性。因此,如果您执行DefaultIfEmpty
和user.Username
之类的操作为null,则会获得user
。然后,您可以在每次访问NullReferenceException
时检查空值,也可以在调用user
或select
之前投影(即SingleOrDefault
) 。毕竟,空用户序列会选择空用户名序列 - 在DefaultIfEmpty
创建名称或SingleOrDefault
之后,无需任何手册null
- 检查。
答案 1 :(得分:1)
进行群组加入,然后通过查询来解压缩群组。当集合为空时,DefaultIfEmpty会生成一个null元素。
var messageUsers = (
from pm in dc.PrivateMessages
join u in dc.Users
on pm.SenderID equals u.UserID
into users
from user in users.DefaultIfEmpty()
where !pm.IsDeletedRecipient && pm.RecipientID == id
...
此外,如果在dbml中的表之间设置了关联,则应该有一个从PrivateMessage到User的关系属性,可以用来更简单地表达查询。 (我将该属性命名为Senders,但它可能是自动命名为Users或Users1。您可以在dbml中重命名该属性。)
var messageUsers = (
from pm in dc.PrivateMessages
where !pm.IsDeletedRecipient && pm.RecipientID == id
from user in pm.Senders.DefaultIfEmpty()
...