当使用Func <TModel,TResult>而不是内联选择器时,Linq2SQL n + 1

Nic*_*sen 1 c# linq-to-sql

我有一个Linq2SQL上下文,有2个表,一个用于Users,一个用于Posts.最初我有这个查询:

var results = db.Users.Select(m => new UserModel
        {
            Id = m.Id,
            DisplayName = m.DisplayName,
            PostCount = m.Posts.Count(),
        }).ToList();
Run Code Online (Sandbox Code Playgroud)

这很有效,没有n + 1.然后我决定编写第二个以不同方式过滤用户的函数,并认为我会聪明并将select移动到a Func<User, UserModel>然后从我的两个查询中调用它.此查询特别更改为如下所示:

Func<User, UserModel> UserModelSelector =
        m => new UserModel
        {
            Id = m.Id,
            DisplayName = m.DisplayName,
            PostCount = m.Posts.Count(),
        };

var results = db.Users.Select(UserModelSelector).ToList();
Run Code Online (Sandbox Code Playgroud)

只有现在这个查询通过加载每个User单独的帖子计数得到n + 1 .我已经尝试过将其设置为public/private/internal,readonly,static的所有组合,并且在所有情况下都会出现n + 1.

任何人都可以解释这里发生了什么?

Jon*_*Jon 5

您已将选择器定义为lambda,因此LINQ没有选项,只能获取用户,然后依次对每个用户执行选择器,从而产生n + 1.

您可以通过将其定义为表达式树来避免这种情况:

Expression<Func<User, UserModel>> UserModelSelector = 
    m => new UserModel 
    { 
        Id = m.Id, 
        DisplayName = m.DisplayName, 
        PostCount = m.Posts.Count(), 
    }; 
Run Code Online (Sandbox Code Playgroud)

这允许LINQ将整个投影转换为SQL并将其作为单个查询执行.当然,在表达式树中,您只能使用可以转换为SQL的构造,但在这种情况下,一切都很好,因为我们可以从您的初始方法中看到并知道.