【发布时间】:2020-11-22 17:48:00
【问题描述】:
我想使用 Entity Framework 删除重复记录。
这是我尝试过的
var result = _context.History
.GroupBy(s => new
{
s.Date,
s.EventId
})
.SelectMany(grp => grp.Skip(1)).ToList();
_context.History.RemoveRange(result);
await _context.SaveChangesAsync();
但我得到一个错误
System.InvalidOperationException:“NavigationExpandingExpressionVisitor”处理 LINQ 表达式“grp => grp.Skip(1)”失败。这可能表明 EF Core 中存在错误或限制
我知道这是对 Entity Framework 的重大更改,但我真的不知道如何更新我的代码。
【问题讨论】:
-
首先不要使用 EF Core。 EF Core 是 ORM,而不是 SQL 替代品。这里没有对象,删除重复项最简单、最有效的方法是使用带有
ROW_NUMBER()的 CTE,它将返回所有倍数,按您想要的任何排序顺序排列,允许您选择要保留的行 -
例如
with dups as (select *, row_number() over (partition by date,eventid order by id desc) rn from...) delete dups where rn>1将删除除最大 id 之外的所有重复项。 CTE 不需要返回所有列,只需要键列就足够了。您可以指定不同的ORDER BY来选择不同的行来保留 -
@PanagiotisKanavos 这个 CTE 数据库是不可知论的还是只是 SqlServer 特定的? ORM 可能不是 SQL 的替代品,但 LINQ 应该是抽象和与数据库无关的语言集成的查询语言,那为什么不使用它呢? EF Core 因不愿意翻译而违反合同这一事实并不意味着 OP 做错了什么。
-
@IvanStoev 该操作与对象无关。不涉及任何对象。 LINQ 并不打算处理这种情况。 ORM 从来都不是用来报告查询或完全替代 SQL 的。如果你用
ANSI standard替换database agnostic,是的,它是ANSI标准,甚至在MySQL 8之后的MySQL中也支持。所有其他主要数据库已经有ROW_NUMBER() -
@IvanStoev 和 SQLite 在 version 3.25 中添加了窗口函数。此外,OP 试图做的事情在 SQL 中没有意义——该组并不是真正的分组,并且 SQL 中没有 SKIP。这是试图将(有点低效)LINQ-to-Objects 操作应用于数据库,希望 EF Core 能够以某种方式将其转换为 SQL
标签: c# .net entity-framework asp.net-core entity-framework-core