【问题标题】:Can this EF query be optimized?可以优化此 EF 查询吗?
【发布时间】:2011-05-27 18:47:19
【问题描述】:

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

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

当 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 ) );

这个查询会有效吗?考虑到User.IDUserProfile.UserID 是一对一的,有什么方法可以在不加载SenderUser 的情况下加载SenderUser.UserProfile.Image?我想我需要为此使用 LINQ JOIN。这是正确的吗?

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

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

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

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

谢谢。

【问题讨论】:

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


    【解决方案1】:

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

    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
    

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

    【讨论】:

    • 谢谢。最后,我尝试了手动joins 和使用Select 的投影,看起来Select 生成的连接稍微重一些,但更易于维护,所以我将保持原样。
    【解决方案2】:

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

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

    【讨论】:

    • 感谢您的回复!想象一下约翰给蕾哈娜发了很多信息。她会收到一个收件箱,里面装满了他的消息(还有他的照片!),但不知道他的照片会在列表加载之前重复出现。
    • 所以先加载消息,然后在单独的查询中加载所有发件人的图像。否则,您可能会收到来自同一用户的 100 条消息并加载他的图像 100 次。
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-07-21
      • 2012-06-27
      • 1970-01-01
      • 1970-01-01
      • 2019-02-24
      • 1970-01-01
      • 2021-02-20
      • 1970-01-01
      相关资源
      最近更新 更多