EF Core 按列不同

Jer*_*myB 4 c# sql-server entity-framework entity-framework-core

在 EF 6 中,如果我想通过不同的姓氏选择用户,我可以这样做:

var users = _context.User
            .GroupBy(x => x.LastName)
            .Select(x => x.FirstOrDefault())
            .OrderBy(x => x.LastName)
            .Take(10)
            .ToList();
Run Code Online (Sandbox Code Playgroud)

在 EF Core 3.1.6 中,这个相同的查询给了我以下异常:

System.InvalidOperationException: The LINQ expression '(GroupByShaperExpression:
KeySelector: (u.LastName), 
ElementSelector:(EntityShaperExpression: 
    EntityType: User
    ValueBufferExpression: 
        (ProjectionBindingExpression: EmptyProjectionMember)
    IsNullable: False
)
)
    .FirstOrDefault()' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync()
Run Code Online (Sandbox Code Playgroud)

有没有办法在不使用 AsEnumerable (或其他替代方法)的情况下使用该查询,这会将整个巨大的表加载到内存中?我在下面使用的数据库是 Microsoft SQL Server 2014,它可以处理这种查询。

Iva*_*oev 7

EF Core 5 可能会支持这种类型的查询(EF Core GitHub 存储库中肯定存在未解决的问题)。

EF Core 3.x 中的解决方法类似于How to select top N rows for each group in a Entity Framework GroupBy with EF 3.1 - (1) 使用子查询来选择不同的键值和 (2) 然后加入/关联它主查询结合限制运算符(在本例中为Take(1)):

var users = _context.User.Select(x => x.LastName).Distinct() // (1)
    .SelectMany(key => _context.User.Where(x => x.LastName == key).Take(1)) // (2)
    // the rest is the same as the origonal
    .OrderBy(x => x.LastName)
    .Take(10)
    .ToList();
Run Code Online (Sandbox Code Playgroud)

  • 是不是很骇人听闻?甚至 LINQ-to-SQL 也能正确翻译它!这种解决方法很奇特,但这样的限制会让许多开发人员望而却步。嗯,你知道这一切。值得一提的一个缺点是,投影仍然会选择子查询中的整个记录​​,并且仅影响主查询的字段列表。除非您愿意在子查询中重复投影(包括分组键)。叹... (2认同)