可以优化此EF查询吗?

时间:2011-05-27 10:16:22

标签: c# entity-framework entity-framework-4 linq-to-entities

我是Entity Framework的新手,不确定何时使用预先加载和Include,何时使用Select的LINQ查询,以及何时按需加载实体。我也不知道EF是否以及何时缓存实体。 (是的,我最终会阅读文档: - )

我正在构建ASP .NET MVC网站内部的消息传递系统,性能非常重要。想象一下以下场景。

当蕾哈娜进入她的收件箱时,她需要查看一个邮件列表,每个邮件都有发件人的姓名和图片。想象一下约翰为他的新歌写了蕾哈娜的歌词。在她的收件箱中,有一条关于约翰的照片的信息。当John进入他的发件箱时,他看到了与Rihanna的名字和图片相同的信息。

因此,当我们从数据库中获取消息时,我们可能需要发件人和收件人个人资料图片。想象一下以下查询:

private static Func<MyEntities, int, Message> _getMessageByIdQuery = CompiledQuery.Compile(
    ( MyEntities ctx, int messageId ) => ctx.Messages
        .Include( "SenderUser" )
        .Include( "SenderUser.UserProfile.Image" )
        .Include( "RecipientUser" )
        .Include( "RecipientUser.UserProfile.Image" )
        .SingleOrDefault( message => message.ID == messageId ) );

此查询是否有效?有没有办法加载SenderUser.UserProfile.Image而不加载SenderUser,考虑到User.IDUserProfile.UserID是一对一的?我想我需要使用LINQ JOIN。这是对的吗?

使用LINQ以避免在只需要一个字段时加载所有字段(例如仅从ImageID加载UserProfile)是否更有效?

使用代码中某处的Load做同样的事情会更好吗?

这样的查询每次都会转到数据库吗?想象一下,我们有一千条消息,都来自同一个人。我们每次都会查询他的Image吗?

我正在使用EF 4和ASP .NET MVC 3.

感谢。

3 个答案:

答案 0 :(得分:3)

一种方法是直接从查询中发送自定义显示/数据对象,这样您就不需要加载额外的对象。例如:

var dto = ctx.Messages
          .Where(whereclause)
          .Select(m=> new DTOTYPE
                         {Id = m.Id, 
                          Content= m.Content, 
                          SenderId = m.SenderUser.Id, 
                          SenderImage = m.SenderUser.UserProfile.Image, 
                          SenderImageId = m.SenderUser.UserProfile.ImageId}) 
                         //more fields if you need any

这将取决于您的情况,但这样您不必疯狂包括所有。但是您需要管理您的视图/数据对象,因为它们可能会因许多不同的屏幕和视图而失控。希望这可以帮助。

答案 1 :(得分:1)

使用@ AD.Net提议的投影。使用投影时,您可以传输您真正需要的数据,而不是整个对象,这些对象都是您从未使用过的属性。请注意,每次查询数据库中的消息时,这确实会加载图片。

如果您计划显示来自同一用户的更多邮件,请在单独查询中仅加载一次图片!此外,收件人是否真的需要加载他的图像?如果是,为什么不在登录时只加载一次图像并将其保存在会话中,而不是为收件箱中的每条消息加载相同的数据?

答案 2 :(得分:0)

没有人能告诉您代码的执行情况,您必须进行基准测试。 是的,如果使用连接,则可以避免加载SenderUser。如果您想知道如何查看生成的sql代码,请查看here