EF core 2.1使用投影

时间:2018-10-21 11:29:40

标签: c# .net-core ef-core-2.1

我想在投影中使用Take(),但我不想产生N + 1查询,此外在投影中没有Take()时,我还面临性能问题。 我在EF6上使用了Take(),但在EF Core上却遇到了N + 1问题。

投影示例:

source.Select(post => new PostProject
            {
                PostDisableCoins = post.PostDisableCoins
                                    .OrderBy(x=>x.CoinAmount)
                                    .Take(3)
                                    .ToList(),
                WarStartTime = post.WarStartTime,
                WarEndTime = post.WarEndTime,
                WarWinner = post.WarWinner,
                WarDeclarer = post.WarDeclarer
            }); 

我想在没有N + 1的情况下使用Take(3),有什么建议吗?!?

2 个答案:

答案 0 :(得分:1)

请注意有关EF core 2.1 new features:

的文档
  

我们改进了查询翻译,以避免执行“ N + 1” SQL   在许多使用导航的常见方案中查询   投影中的属性导致根查询中的数据联接   来自相关子查询的数据。 优化需要   缓冲子查询的结果,我们要求您   修改查询以选择采用新行为

例如:

var query = context.Customers.Select(
    c => c.Orders.Where(o => o.Amount  > 100).Select(o => o.Amount).ToList());

请注意,其中包含.ToList()

您需要相应地修改投影查询,以启用优化功能。


您的情况可能是:

source.Select(post => new PostProject
            {
                PostDisableCoins = post.PostDisableCoins
                                    .Select(x => x.OrderBy(x=>x.CoinAmount))
                                    .Select(x => x) 
                                    .Take(3)                                  
                                    .ToList(),
                WarStartTime = post.WarStartTime,
                WarEndTime = post.WarEndTime,
                WarWinner = post.WarWinner,
                WarDeclarer = post.WarDeclarer
            }); 

答案 1 :(得分:1)

这是EF Core 2.1实施缺陷。以下是变通办法,但仅在确实存在性能问题时才使用它,因为它需要打破导航属性联接抽象并使用手动联接,我总是说这不应与EF(Core)一起使用。如果用于投影多个集合或作为更复杂的查询的一部分,也可能不起作用。

这要求使用横向联接将post.PostDisableCoins集合导航属性SelectMany的用法替换为OrderBy并隐藏Take / var postDisableCoinsQuery = source.SelectMany(p => db.Set<PostDisableCoin>() .Where(c => c.PostId == p.Id) .OrderByDescending(c => c.CoinAmount) .Take(3) ); 运算符(使用正确的类型和PK / FK名称):

GroupJoin

然后对它进行var query = from p in source join c in postDisableCoinsQuery on p.Id equals c.PostId into postDisableCoins select new PostProject { PostDisableCoins = postDisableCoins.ToList(), WarStartTime = p.WarStartTime, WarEndTime = p.WarEndTime, WarWinner = p.WarWinner, WarDeclarer = post.WarDeclarer };

import { NgModule } from '@angular/core';
import { Http, RequestOptions } from '@angular/http';
import { AuthHttp, AuthConfig } from 'angular2-jwt';

export function authHttpServiceFactory(http: Http, options: RequestOptions) {
  return new AuthHttp(new AuthConfig({
    tokenName: 'token',
        tokenGetter: (() => sessionStorage.getItem('token')),
        globalHeaders: [{'Content-Type':'application/json'}],
    }), http, options);
}

@NgModule({
  providers: [
    {
      provide: AuthHttp,
      useFactory: authHttpServiceFactory,
      deps: [Http, RequestOptions]
    }
  ]
})
export class AuthModule {}

执行后,上面的代码将通过单个SQL查询产生所需的结果。