我有两个表作为消息传递系统的一部分:
RECIPIENTS
RecipientId (PK)
RecipientMemberId (FK to user table)
MessageId (FK to message table)
...
MESSAGES
MessageId (PK)
...
和这两个linq查询:
IEnumerable<int> myMessageIds = recipientRepository.Recipients.Where(x => x.RecipientMemberId == User.Identity.GetUserId()).Select(x => x.MessageId);
IEnumerable<Message> inboxMessages = messageRepository.Messages.Where(x => myMessageIds.Contains(x.MessageId));
为其收件箱提取用户的邮件。
问题:
这有效,但我有一种令人讨厌的感觉,我做错了。这效率低吗?为了好玩,有哪些替代linq查询会更有效地产生相同的结果?任何其他评论也表示赞赏。
谢谢。
答案 0 :(得分:1)
你在做什么没有错。只要您使用主键,索引或外键查询表,RDMS就会对其进行完美优化。
在你的情况下:
IEnumerable<int> myMessageIds
= recipientRepository.Recipients
.Where(x => x.RecipientMemberId == User.Identity.GetUserId())
.Select(x => x.MessageId);
您使用的是RecipientMemberId,这是一个外键。如果需要,可以使用linq而不是lambda表达式重写相同的查询:
var myMessageIds = from recipient in recipientRepository.Recipients
let userId = User.Identity.GetUserId() // done only once
where recipient.RecipientMemberId == userId
select recipient.MessageId;
第二个问题也是如此:
var inboxMessages = from message in messageRepository.Messages
where myMessageIds.Contains(message.MessageId)
select message;
答案 1 :(得分:1)
var userId = User.Identity.GetUserID();
IEnumerable<Message> inboxMessages = Context
.Messages
.Where(x => Context.Recipients
.Where(r => r.RecipientMemberId == userId)
.Any(r => x.MessageId == r.MessageId));
但更重要的是,应该在收件人和邮件上有导航属性。
public class Recipient
{
.....
[Key]
public int Id { get; set; } // If this is your PK
public virtual ICollection<Message> Messages { get; set; } // navigational Property to Messages
}
和您的留言:
public class Message
{
.....
[Key]
public int Id { get; set; } // If this is your PK
public int RecipientId { get; set; } // This would be FK
public virtual Recipient Recipient { get; set; } // navigational property back to Recipient
}
然后你可以做类似的事情:
var recipient = Context.Recipients
.Where(x => x.RecipientMemberId == userId)
.FirstOrDefault()
var messages = recipient.Messages.ToList();
注意,这将对数据库进行2次调用,一次是在收到收件人时。当您访问虚拟消息属性时,另一个。
为了优化这一点,您可以在其查询中告知EF“Include
”一个导航属性,然后进行连接。
E.g。
var recipient = Context.Recipients
.Include(x => x.Messages)
.Where(x => x.RecipientMemberId == userId)
.FirstOrDefault()
答案 2 :(得分:1)
您经常可以通过导航属性访问相关数据。如果您先通过代码创建表,它们看起来像这样:
public class Recipient
{
public int RecipientId { get; set; }
public virtual Icollection<Message> Messages { get; set; }
// etc
}
public class Message
{
public int MessageId { get; set; }
public virtual Recipient Recipient { get; set; }
// etc
}
edmx或dbml文件将生成类似的属性。
IEnumerable<Message> myMessages = recipientRepository.Recipients.Where(x => x.RecipientMemberId == User.Identity.GetUserId()).SingleOrDefault().Messages;