有個古老資料庫,裡面還有NTEXT型別欄位(SQL 2005加入NVARCHAR(MAX)後,應該沒人想用TEXT/NTEXT了),用Dapper執行一段SQL更新NTEXT欄位,發生古怪錯誤。

指令如下:

cn.Execute("UPDATE SomeTable SET NTextField = @data WHERE Id = 1", new { data = "…" });

錯誤訊息為:sql_variant is incompatible with ntext

System.Data.SqlClient.SqlException (0x80131904): Operand type clash: sql_variant is incompatible with ntext
   於 System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   於 System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   於 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   於 System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   於 System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
   於 System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
   於 System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
   於 System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
   於 System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
   於 Dapper.SqlMapper.ExecuteCommand(IDbConnection cnn, CommandDefinition& command, Action`2 paramReader) 於 D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs: 行 2802
   於 Dapper.SqlMapper.ExecuteImpl(IDbConnection cnn, CommandDefinition& command) 於 D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs: 行 1060
   於 Dapper.SqlMapper.Execute(IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Nullable`1 commandTimeout, Nullable`1 commandType) 於 D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs: 行 995
   於 Managers.ApiService.UpdateBlah(Guid id, String userId, String reason) 於 X:\TFS\Boo\MAIN\src\WebApi\ApiService.cs: 行 847

第一次看到sql_variant型別,依文件所說,sql_variant常用於資料行、參數、變數及使用者定義函數的傳回值中,不能用來儲存varchar(max)、nvarchar(max)、text、ntext、xml… 等,最大長度為8016 Bytes。

推測Dapper在底層用sql_variant來存放@data參數字串,在指定給NTextField欄位時產生錯誤。爬文找不到有人反應類似問題,猜想原因是會Dapper的新世代不會摸到NTEXT,而存取NTEXT欄位的程式還停在ASP、VB6、ADO.NET世界打滾,像我這樣用3D印表機印尪仔標,算是少數中的少數。 XD

福至心靈,既屬Dapper內部行為,這様算Bug嗎?如果是Bug,後來有修正嗎?用NuGet Manager查Dapper版本還停在1.26.0,而最新版已到1.42.0。

處理軟體茶包的SOP,先更新到最新版再說。更新至1.42.0,不藥而瘉,結案~


Comments

Be the first to post a comment

Post a comment