[已解決] C# 內送的表格式資料流 (TDS) 遠端程序呼叫 (RPC) 通訊協定資料流不正確。

今天出現了一個 bug,錯誤訊息如下:
    
[ERR] An exception occurred in the database while saving changes for context type 'ActivityDbContext'.
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
 ---> Microsoft.Data.SqlClient.SqlException (0x80131904): 內送的表格式資料流 (TDS) 遠端程序呼叫 (RPC) 通訊協定資料流不正確。參數 6 ("@p3"): 資料類型 0xA7 具有無效的資料長度或中繼資料長度。
   at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at Microsoft.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
   at Microsoft.Data.SqlClient.SqlDataReader.get_MetaData()
   at Microsoft.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)
   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean isAsync, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String method)
   at Microsoft.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior)
   at Microsoft.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)
ClientConnectionId:aaaa3bc3-ffff-cccc-beea-3343371f812d
    

主要錯誤訊息應該是:
    
(0x80131904): 內送的表格式資料流 (TDS) 遠端程序呼叫 (RPC) 通訊協定資料流不正確。參數 6 ("@p3"): 資料類型 0xA7 具有無效的資料長度或中繼資料長度。
    

再查看更上層的錯誤訊息後,找到這裡 @p3 代表的資料欄位,發現在資料庫中的資料類型是 varchar(max) 。查看資料庫紀錄後發現在 C# 程式端就被擋掉,沒有實際執行到資料庫中,平時可以正常執行,但只要此欄位的內容太多就會出現這個錯誤訊息,很容易重現。

因為是在程式中就被擋掉,而此 Model 是使用 dotnet ef dbcontext scaffold 透過資料庫產生的,比對過後發現此欄位有 Unicode 這個 Attribute:
    
[Table("my_table")]
[Index("Id", Name = "my_table_id_uindex", IsUnique = true)]
public partial class MyTable
{
    [Column("my_col")]
    [Unicode(false)]
    public string? MyCol { get; set; }
}
    

於是嘗試將資料庫欄位由 varchar(max) 改為 nvachar(max),並將此 Model 的 UnicodeAttribute 移除,實測不會再次出現錯誤。紀錄一下希望能夠幫助同樣在加班的網友...

留言