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

使用Dapper调用分页存储过程返回重复值问题求助

问题:Dapper调用分页存储过程返回重复记录

数据库共30条记录,使用Dapper调用存储过程分页时,每次返回的结果存在重复值。

现有代码

C# 代码

IEnumerable<TEntity> entities;
DynamicParameters parameters = new DynamicParameters();
parameters.Add("@page", page, DbType.Int32, ParameterDirection.Input);
parameters.Add("@pageSize", pageSize, DbType.Int32, ParameterDirection.Input);
parameters.Add("@search", search, DbType.String, ParameterDirection.Input);

try
{
    _connection.Open();
    entities = await _connection.QueryAsync<TEntity>($"{storedProcedure}", parameters);
}
catch (Exception)
{
    return null;
}
finally
{
    _connection.Dispose();
    _connection.Close();
}

return entities.ToList();

存储过程代码

ALTER PROCEDURE [dbo].[SP_GetCategories]
    @search nvarchar(300) = '',
    @page int = 1,
    @pageSize int = 10
AS
BEGIN
    SET @page = (@page - 1) * @pageSize;
    DECLARE @Sql Nvarchar(800)
    SET @Sql=' select * from Dy.Category As C With(Nolock) where  IsDeleted=0 ';

    IF @search IS NOT NULL AND @search <> ''
    BEGIN
        SET @Sql=@Sql+' AND C.Title like N''%''' +@search +'''%'' ' ;
    END

    SET @Sql = @Sql +' Order By CreateTime Desc OFFSET '+CAST(@page AS NVARCHAR(100))+

' ROWS FETCH NEXT ' +CAST(@pageSize AS NVARCHAR(100))+' ROWS ONLY';

    EXEC sp_executesql @Sql
END

问题原因及修复方案

1. 排序不稳定导致分页重复

当前存储过程仅用CreateTime Desc排序,若存在多条记录的CreateTime完全相同,SQL Server的OFFSET/FETCH无法保证稳定的排序顺序,不同分页请求可能返回重复的记录,或跳过部分记录。

修复存储过程的排序逻辑:
在排序条件后添加唯一标识字段(如主键Id),确保排序的唯一性和稳定性:

SET @Sql = @Sql +' Order By CreateTime Desc, Id Desc OFFSET '+CAST(@page AS NVARCHAR(100))+
' ROWS FETCH NEXT ' +CAST(@pageSize AS NVARCHAR(100))+' ROWS ONLY';

2. 数据库连接管理错误

C#代码中finally块先调用_connection.Dispose()再调用_connection.Close(),这是错误的:Dispose()方法会自动关闭并释放连接资源,后续的Close()调用无意义,甚至可能引发异常。

优化连接管理:
使用using语句自动管理连接生命周期,无需手动调用Open()、Close()和Dispose(),同时显式指定命令类型为存储过程:

DynamicParameters parameters = new DynamicParameters();
parameters.Add("@page", page, DbType.Int32, ParameterDirection.Input);
parameters.Add("@pageSize", pageSize, DbType.Int32, ParameterDirection.Input);
parameters.Add("@search", search, DbType.String, ParameterDirection.Input);

using (var conn = _connection)
{
    try
    {
        await conn.OpenAsync();
        var entities = await conn.QueryAsync<TEntity>(
            storedProcedure, 
            parameters, 
            commandType: CommandType.StoredProcedure
        );
        return entities.ToList();
    }
    catch (Exception)
    {
        return null;
    }
}

3. 动态SQL的SQL注入风险(额外优化)

存储过程中直接拼接@search参数到动态SQL存在SQL注入风险,应改用参数化查询:

ALTER PROCEDURE [dbo].[SP_GetCategories]
    @search nvarchar(300) = '',
    @page int = 1,
    @pageSize int = 10
AS
BEGIN
    SET @page = (@page - 1) * @pageSize;
    DECLARE @Sql Nvarchar(800)
    SET @Sql=' select * from Dy.Category As C With(Nolock) where  IsDeleted=0 ';

    IF @search IS NOT NULL AND @search <> ''
    BEGIN
        SET @Sql=@Sql+' AND C.Title like N''%'' + @search + ''%'' ' ;
    END

    SET @Sql = @Sql +' Order By CreateTime Desc, Id Desc OFFSET '+CAST(@page AS NVARCHAR(100))+
' ROWS FETCH NEXT ' +CAST(@pageSize AS NVARCHAR(100))+' ROWS ONLY';

    EXEC sp_executesql @Sql, N'@search nvarchar(300)', @search = @search;
END

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 07:12:06