Linq - 从两个表中提取数据 - 效率 - 替代linq查询

时间:2015-03-25 23:30:07

标签: c# sql-server linq entity-framework

我有两个表作为消息传递系统的一部分:

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查询会更有效地产生相同的结果?任何其他评论也表示赞赏。

谢谢。

3 个答案:

答案 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;