如何将多层复杂模型绑定到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
相关产品推荐
相关产品推荐

