You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将含ROW_NUMBER的SQL删除语句转换为EF Core 5 Lambda表达式

解决方案1:使用EF Core内置RowNumber窗口函数(性能最优,适配你原SQL逻辑)

EF Core 5 原生支持通过EF.Functions.RowNumber调用SQL的ROW_NUMBER窗口函数,和你原SQL的CTE逻辑完全对应:

// 替换为你实际的Col1过滤值
var targetColValue = "你要过滤的Col1参数值";

// 构造需要删除的记录查询
var deleteQuery = _unitOfWork.tables
    .Where(t => t.Col1 == targetColValue)
    .Select(t => new 
    {
        t,
        RowNum = EF.Functions.RowNumber(
            ordering: EF.Property<DateTime>(t, nameof(Table.Col2)), // 这里把DateTime替换为Col2实际的类型
            sortOrder: SortOrder.Descending)
    })
    .Where(x => x.RowNum > 10)
    .Select(x => x.t);

// 直接传入查询执行批量删除
await _unitOfWork.tables.DeleteAsync(deleteQuery);

注意:该方案需要你使用EF Core官方SqlServer数据库提供者,会自动生成和你示例几乎一致的CTE删除SQL,无需加载实体到内存,性能最高。
额外提醒:不要使用LINQ自带的Select((item, index) => ...)重载计算行号,该重载会将所有符合条件的记录加载到内存后再计算行号,数据量大时性能极低,一定要用EF.Functions.RowNumber生成数据库端执行的窗口函数。


解决方案2:兼容所有EF Core版本的通用写法(无窗口函数依赖)

如果你不方便使用窗口函数,也可以通过先查询要保留的前10条主键,再反向删除剩余记录的方式实现,逻辑更直观:

var targetColValue = "你要过滤的Col1参数值";

// 查出需要保留的前10条记录的主键(假设你的表主键为Id,自行替换为实际主键字段)
var keepIds = await _unitOfWork.tables
    .Where(t => t.Col1 == targetColValue)
    .OrderByDescending(t => t.Col2)
    .Take(10)
    .Select(t => t.Id)
    .ToListAsync();

// 传入删除条件:匹配Col1且不在保留列表中
await _unitOfWork.tables.DeleteAsync(t => t.Col1 == targetColValue && !keepIds.Contains(t.Id));

注意:该方案需要将保留的主键加载到内存,适合单批次过滤后数据量不大的场景,如果数据量极大推荐使用方案1。


内容的提问来源于stack exchange,提问作者Glen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 17:54:04