当使用Func<;TModel,TResult>;而不是内联选择器
本文关键字:选择器 gt Func lt TModel TResult | 更新日期: 2023-09-27 18:20:47
我有一个带有两个表的Linq2SQL上下文,一个表用于Users
,一个用于Posts
。最初我有这样的疑问:
var results = db.Users.Select(m => new UserModel
{
Id = m.Id,
DisplayName = m.DisplayName,
PostCount = m.Posts.Count(),
}).ToList();
这很有效,没有n+1。然后,我决定编写第二个函数,以不同的方式过滤用户,并认为我会很聪明,将select移到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();
只是现在,这个查询通过单独加载每个User
的post计数来产生n+1。我尝试过将其公开/私有/内部、只读、静态的每一种组合,在所有情况下都会出现n+1。
有人能解释一下这里发生了什么吗
您已经将选择器定义为lambda,因此LINQ别无选择,只能获取用户,然后依次对每个用户执行选择器,结果是n+1。
您可以通过将其定义为表达式树来避免这种情况:
Expression<Func<User, UserModel>> UserModelSelector =
m => new UserModel
{
Id = m.Id,
DisplayName = m.DisplayName,
PostCount = m.Posts.Count(),
};
这允许LINQ将整个投影转换为SQL,并将其作为单个查询执行。当然,在表达式树中,您只能使用可以转换为SQL的构造,但在这种情况下,一切都很好,正如我们从您最初的方法中看到和知道的那样。