EntityFramework核心组通过给我一个订单

时间:2018-01-03 17:29:11

标签: entity-framework-core

这是我的linq to sql查询:

var data = 
    from p in dbcontext.person
    group p by p.city.ToLower() into g
    select new StatsViewModel { city = g.Key, citizen_count = g.Count() };

这是我在sql server中获得的真正的sql查询:

SELECT [p0].[id_person], [p0]....
      FROM [person] AS [p0]
      ORDER BY LOWER([p0].[city])

这是一个订单,而不是一个小组...

2 个答案:

答案 0 :(得分:6)

这是当前EF Core的GroupBy转换的已知问题,由Relational: Support translating GroupBy() to SQL #2341跟踪并承诺在下一个EF Core 2.1版本中修复(根据EF Core Roadmap })。所以在那之前,你无能为力。

但不要被生成的SQL所欺骗。 EF Core使用所谓的Cliend and Server Evaluation的组合,在这种特殊情况下意味着在检索到您看到的SQL查询的结果后,GroupBy将在内存中执行,因此实际结果将是正确的。 "只有"问题可能是表现。

答案 1 :(得分:1)

使用debug(Microsoft.Extensions.Logging)我可以确认linq的.Net Core EF 2.0.1组没有转换为SQL。提出警告:

  

LINQ表达式'GroupBy([p] .City.ToLower(),[p])'无法   将被翻译并在本地进行评估。

dbug: Microsoft.EntityFrameworkCore.Query[10104]
      => Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor
      Optimized query model: 
      'from IGrouping<string, Person> g in 
          (from Person p in DbSet<Person>
          select [p]).GroupBy([p].City.ToLower(), [p])
      select new <>f__AnonymousType0<string, int>(
          [g].Key, 

              (from Person <generated>_1 in [g]
              select [<generated>_1]).Count()
      )'

发出警告:

warn: Microsoft.EntityFrameworkCore.Query[20500]
      => Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor
      The LINQ expression 'GroupBy([p].City.ToLower(), [p])' could not
      be translated and will be evaluated locally.

结果由当地组成:

dbug: Microsoft.EntityFrameworkCore.Query[10107]
      => Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor
      (QueryContext queryContext) => IEnumerable<<>f__AnonymousType0<string, int>> _InterceptExceptions(
          source: IEnumerable<<>f__AnonymousType0<string, int>> _Select(
              source: IEnumerable<IGrouping<string, Person>> _GroupBy(
                  source: IEnumerable<Person> _ShapedQuery(
                      queryContext: queryContext, 
                      shaperCommandContext: SelectExpression: 
                          SELECT "p0"."ID", "p0"."City", "p0"."Name"
                          FROM "People" AS "p0"
                          ORDER BY lower("p0"."City"), 
                      shaper: UnbufferedEntityShaper<Person>), 
                  keySelector: (Person p) => string p.City.ToLower(), 
                  elementSelector: (Person p) => p), 
              selector: (IGrouping<string, Person> g) => new <>f__AnonymousType0<string, int>(
                  g.Key, 
                  int Count(g)
              )), 
          contextType: ConsoleApplication3.MyContext, 
          logger: DiagnosticsLogger<Query>, 
          queryContext: queryContext)

这是重现它的代码:

我在这里发布源代码,以帮助那些想知道如何跟踪它的人:

模型和dbcontext

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Console;

namespace ConsoleApplication3
{
    public class Person
    {

        public int ID { get; set; }
        public string Name{ get; set; }
        public string City { get; set; }

    }

    public class MyContext : DbContext
    {

        public static readonly LoggerFactory MyLoggerFactory
            = new LoggerFactory(new[] {new ConsoleLoggerProvider((_, __) => true, true)});

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlite("Data Source=beer.db"); //Available here
            optionsBuilder.UseLoggerFactory(MyLoggerFactory);
            base.OnConfiguring(optionsBuilder);
        }

        public DbSet<Person> People { get; set; }
    }

}

插入数据并进行查询

        var ctx =new  MyContext();

        var p1=new Person();
        p1.City = "L'Escala";
        p1.Name = "Dani";
        ctx.People.Add(p1);

        var p2=new Person();
        p2.City = "L'Escala";
        p2.Name = "Dolors";
        ctx.People.Add(p2);

        var p3=new Person();
        p3.City = "Albons";
        p3.Name = "Joan";
        ctx.People.Add(p3);

        ctx.SaveChanges();

        var data1 = 
            from p in ctx.People
            group p by p.City.ToLower() into g
            select new { city = g.Key, citizen_count = g.Count() };

        data1.ToList();

        foreach (var v in data1)
        {
            Console.WriteLine($"{v.city} - {v.citizen_count}");
        }        

结果:

结果还可以:

albons - 1
l'escala - 2

解决方案:

看起来group by will be supported on next 2.1,评估一下这次是否能解决这个性能问题。