• Entity Framework 使用注意:Where查询条件中用到的关联实体不需要Include


    来自博客园开发团队开发前线最新消息:

    在Entity Framework中,如果实体A关联了实体B,你想在加载实体A的同时加载实体B。通常做法是在LINQ查询中使用Include()。但是,如果你在查询条件中用到了实体B,EF会自动加载实体B,这时Include不仅是多余的,而且还会增加额外的LEFT OUTER JOIN查询,影响性能。 

    请看我们在博问开发中遭遇这个问题时的一段代码:

    //For q.cnblogs.com
    public class QuestionService 
    {
        private IRepository<QuestionItem> _questionRepository;
    
        public QuestionService(IUnitOfWork unitOfWork)
            : base(unitOfWork)
        {
            _questionRepository = new Repository<QuestionItem>(unitOfWork);
        }
    
        public List<QuestionItem> GetUnsolvedQuestions(int pageIndex, int pageSize)
        {
            return _questionRepository.Entities
                .Include(q => q.User)
                .Where(q => q.IsActive && q.User.IsActive)
                .Skip((pageIndex - 1) * pageSize)
                .Take(pageSize)
                .ToList();
                
        }
    }
    
    public class QuestionItem
    {
        public int Id { get;set; }
        public string Title { get; set; }
        public bool IsActive { get; set; }
        public int UserId { get; set; }
    
        public User User { get; set; }
    }
    
    public class User
    {
        public int UserId { get; set; }
        public bool IsActive {get;set;}
    }

    在上面的代码中,我们想在GetActiveQuestions()返回List<QuestionItem>时,QuestionItem中要包含User信息,所以在LINQ查询使用了.Include(q => q.User)。

    (特别要注意的是:这里把q.User.IsActive作为查询条件之一)

    然后我们用SQL Server Profiler发现,Entity Framework生成了如下的SQL语句:

    SELECT TOP (25) 
    [Filter1].[Id] AS [Id], 
    [Filter1].[Title] AS [Title],
    [Filter1].[UserId] AS [UserId], 
    [Filter1].[UserId1] AS [UserId1], 
    [Filter1].[IsActive1] AS [IsActive], 
    [Filter1].[UserId2] AS [UserId1],
    [Filter1].[IsActive2] AS [IsActive1]
    FROM ( SELECT [Extent1].[Id] AS [Id], [Extent1].[Title] AS [Title], 
    [Extent1].[UserId] AS [UserId1],[Extent1].[IsActive] AS [IsActive1],
    [Extent3].[UserID] AS [UserID2], [Extent3].[IsActive] AS [IsActive2], 
    row_number() OVER (ORDER BY [Extent1].[QID] DESC) AS [row_number]
        FROM   [dbo].[question_Item] AS [Extent1]
        INNER JOIN [dbo].[Users] AS [Extent2] ON [Extent1].[UserID] = [Extent2].[UserID]
        LEFT OUTER JOIN [dbo].[Users] AS [Extent3] ON [Extent1].[UserID] = [Extent3].[UserID]
        WHERE ([Extent1].[IsActive] = 1) AND ([Extent2].[IsActive] = 1) 
    )  AS [Filter1]
    WHERE [Filter1].[row_number] > 0
    ORDER BY [Filter1].[Id] DESC

    [dbo].[Users]表对应的就是User实体类,上面的SQL中[dbo].[Users]出现了两次JOIN,由于[Users]表数据量比较大,两次JOIN影响了执行计划,查询耗时增加。这显然是要避免的。

    在与这个问题一阵激战之后,我们终于找到解决方法 —— 去掉Include,就这么简单!

    从这个地方看,Entity Framework还是挺聪明的,但是由于不知道它的这个聪明之处,反而带来了问题。

    所以,代码如人,要和她相处好,就要了解她的一切!

  • 相关阅读:
    Spring Security简介与入门Demo
    电商项目之多功能增删改查案例
    linux-用户管理
    zabbix3.4配置第三方邮件报警
    zabbix3.4配置客户端配置
    centos7上安装zabbix3.4的详细步骤与问题处理记录
    MyBatis日记(五):一对一关系,一对多关系
    MyBatis日记(四):MyBatis——insert、update、delete、select
    Python日记(二):Python之禅
    Python日记(一):拜见小主——Python
  • 原文地址:https://www.cnblogs.com/dudu/p/entity_framework_include_where.html
Copyright © 2020-2023  润新知