无法保存含图片的Primeng p-editor富文本到SQL,执行存储过程报错
问题描述
使用C# + Dapper将包含Base64大图片的富文本内容(Primeng p-editor的Notes字段)通过用户定义表类型[Test].[ut_InsertRequest]传递给SQL Server存储过程时,抛出异常:Invalid operation. The connection is closed。
- 小图片(5KB左右)可正常保存,18KB图片转Base64后(请求体长度111KB)触发异常
- 用户定义表类型
[Test].[ut_InsertRequest]包含Notes NVARCHAR(Max)列 - 核心代码片段:
var dt = new DataTable(); dt.Columns.Add("Id", typeof(int)); dt.Columns.Add("Notes", typeof(string)); // Notes内容示例:<p><img src=\"data:image/jpeg;base64,/9j/4AAQSkZJ........xgf/9k=\"></p> dt.Rows.Add( request.Id, request.Notes ); using var conn = sqlDbConnectionService.GetIDbConnection(); var result = await conn.QueryAsync<Response>( "[Test].[usp_InsertRequest]", new { tvpRequests = dt.AsTableValuedParameter("[Test].[ut_InsertRequest]"), itemId = 101, }, commandType: CommandType.StoredProcedure );
解决方案
1. 显式打开数据库连接
Dapper默认会自动管理连接的打开/关闭,但大数据异步传输时,可能出现连接被提前释放的情况。显式打开连接可确保操作期间连接持续活跃:
using var conn = sqlDbConnectionService.GetIDbConnection(); await conn.OpenAsync(); // 显式打开连接 var result = await conn.QueryAsync<Response>( "[Test].[usp_InsertRequest]", new { tvpRequests = dt.AsTableValuedParameter("[Test].[ut_InsertRequest]"), itemId = 101, }, commandType: CommandType.StoredProcedure );
2. 增加命令超时时间
大Base64数据传输耗时较长,默认30秒的超时时间可能不够,手动设置更长的超时阈值:
var result = await conn.QueryAsync<Response>( "[Test].[usp_InsertRequest]", new { tvpRequests = dt.AsTableValuedParameter("[Test].[ut_InsertRequest]"), itemId = 101, }, commandType: CommandType.StoredProcedure, commandTimeout: 60 // 设置60秒超时,可按需调整 );
3. 调整连接字符串的数据包大小
SQL Server默认数据包大小为4096字节,大Base64数据可能超出限制导致连接异常。将数据包大小设为最大值32767:
Server=YourServerName;Database=YourDBName;Integrated Security=True;Packet Size=32767;
4. 优化大文本传输方式(推荐)
Base64编码会使数据体积增加约33%,改用VARBINARY(MAX)传输字节数组可减少数据量并避免NVARCHAR处理的潜在问题:
步骤1:修改用户定义表类型
将Notes列类型改为VARBINARY(MAX):
ALTER TYPE [Test].[ut_InsertRequest] ALTER COLUMN Notes VARBINARY(MAX);
步骤2:C#代码中转换为字节数组
var dt = new DataTable(); dt.Columns.Add("Id", typeof(int)); dt.Columns.Add("Notes", typeof(byte[])); // 改为字节数组类型 // 将HTML字符串转为UTF8字节数组 var notesBytes = Encoding.UTF8.GetBytes(request.Notes); dt.Rows.Add(request.Id, notesBytes); using var conn = sqlDbConnectionService.GetIDbConnection(); await conn.OpenAsync(); var result = await conn.QueryAsync<Response>( "[Test].[usp_InsertRequest]", new { tvpRequests = dt.AsTableValuedParameter("[Test].[ut_InsertRequest]"), itemId = 101, }, commandType: CommandType.StoredProcedure );
步骤3:存储过程中转换回字符串
如果需要将字节数组转回字符串使用,可在存储过程中转换:
CAST(Notes AS NVARCHAR(MAX))
5. 检查存储过程和目标表定义
确保存储过程中处理Notes字段时没有截断逻辑,且最终插入的目标表列类型也是NVARCHAR(MAX)或VARBINARY(MAX)。
内容的提问来源于stack exchange,提问作者Kaishu
相关产品推荐
相关产品推荐

