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

如何将多层复杂模型绑定到Dapper DynamicParameters?

嵌套对象通过Dapper传入SQL Server的解决方案

核心结论

直接用DynamicParameters绑定包含嵌套集合/对象的.NET模型(比如你的UserAccount里的List<Team>)不可行——Dapper仅会解析对象的顶层属性,嵌套结构会被忽略,且SQL Server无法直接识别.NET的集合类型。

针对你的场景的可行方案

方案1:序列化为JSON传入(推荐,适配动态嵌套结构)

这是处理任意嵌套数据最灵活的方式,将整个对象或嵌套部分序列化为JSON字符串,传入SQL后用OPENJSON解析处理:

C#代码修改
public UserAccount Read(UserAccount userAccount)
{
    using(var connection = _context.CreateConnection())
    {
        // 将整个UserAccount序列化为JSON字符串
        var userJson = JsonSerializer.Serialize(userAccount);
        
        // 传入JSON参数到SQL函数
        string resultJson = connection.QuerySingle<string>(
            "select dbo.A2Q_0169W_UsersAccountsTBLInfo_JSON(@UserJson)", 
            new { UserJson = userJson }
        );
        
        return JsonSerializer.Deserialize<UserAccount>(resultJson)!;
    }
}
SQL端处理示例

在你的SQL函数中,通过JSON_VALUE解析顶层属性,OPENJSON解析嵌套集合:

CREATE FUNCTION dbo.A2Q_0169W_UsersAccountsTBLInfo_JSON(@UserJson NVARCHAR(MAX))
RETURNS NVARCHAR(MAX)
AS
BEGIN
    DECLARE @InternalUserNumber INT, @Avatar NVARCHAR(MAX);
    
    -- 解析顶层属性
    SELECT 
        @InternalUserNumber = JSON_VALUE(@UserJson, '$.InternalUserNumber'),
        @Avatar = JSON_VALUE(@UserJson, '$.Avatar');
    
    -- 解析嵌套的Teams集合到临时表
    SELECT Id, Description
    INTO #TempTeams
    FROM OPENJSON(@UserJson, '$.Teams')
    WITH (
        Id INT '$.Id',
        Description NVARCHAR(MAX) '$.Description'
    );
    
    -- 业务逻辑处理后,返回JSON格式结果(匹配UserAccount结构)
    RETURN (
        SELECT 
            @InternalUserNumber AS INTERNAL_USER_NUMBER,
            @Avatar AS AVATAR,
            (SELECT Id, Description FROM #TempTeams FOR JSON PATH) AS Teams
        FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
    );
END

方案2:表值参数(TVP,适合固定嵌套结构)

如果你的嵌套结构(比如Team)是固定的,可使用SQL Server表值参数,性能优于JSON,但需要提前在SQL端定义表类型:

1. 先在SQL创建表类型
CREATE TYPE TeamTableType AS TABLE (
    Id INT,
    Description NVARCHAR(MAX)
);
2. C#代码修改

将Teams集合转换为DataTable,作为表值参数传入:

public UserAccount Read(UserAccount userAccount)
{
    using(var connection = _context.CreateConnection())
    {
        // 将Teams转换为DataTable
        var teamsTable = new DataTable();
        teamsTable.Columns.Add("Id", typeof(int));
        teamsTable.Columns.Add("Description", typeof(string));
        
        if(userAccount.Teams != null)
        {
            foreach(var team in userAccount.Teams)
            {
                teamsTable.Rows.Add(team.Id, team.Description);
            }
        }
        
        // 构建参数,包含顶层属性和表值参数
        var parameters = new DynamicParameters();
        parameters.Add("@InternalUserNumber", userAccount.InternalUserNumber);
        parameters.Add("@Avatar", userAccount.Avatar);
        parameters.Add("@Teams", teamsTable, DbType.Object, ParameterDirection.Input);
        
        string resultJson = connection.QuerySingle<string>(
            "select dbo.A2Q_0169W_UsersAccountsTBLInfo_JSON(@InternalUserNumber, @Avatar, @Teams)", 
            parameters
        );
        
        return JsonSerializer.Deserialize<UserAccount>(resultJson)!;
    }
}

方案对比

  • JSON序列化:无需提前定义SQL结构,适配任意嵌套层级,开发效率高,适合动态场景。
  • 表值参数:性能更优,类型安全,适合结构固定、数据量大的嵌套集合场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 12:13:13