dotnetcore / FreeSql

🦄 .NET aot orm, C# orm, VB.NET orm, Mysql orm, Postgresql orm, SqlServer orm, Oracle orm, Sqlite orm, Firebird orm, 达梦 orm, 人大金仓 orm, 神通 orm, 翰高 orm, 南大通用 orm, 虚谷 orm, 国产 orm, Clickhouse orm, QuestDB orm, MsAccess orm.
http://freesql.net
MIT License
3.99k stars 842 forks source link

SqlServer表列类型为TimeSpan,Update出现异常 #1787

Closed LeaFrock closed 3 weeks ago

LeaFrock commented 1 month ago

问题描述及重现代码:

假设SqlServer数据库中有一张表Test,表中有一列字段ActTime。该列采用TimeSpan类型CodeFirst创建——根据FreeSql官方文档,对应的数据库类型为time。

现要将ActTime更新为newActTime(假设是10:00:00):

await FreeSql!.Update<Test>()
                .Where(a => a.Id == id)
                .Set(a => new Test()
                {
                    ActTime = newActTime,
                })
                // .Set(a => a.ActTime, newActTime)
                .ExecuteAffrowsAsync();

出现异常,核心堆栈如下:

System.Exception: 操作数类型冲突: int 与 time 不兼容
 ---> Microsoft.Data.SqlClient.SqlException (0x80131904): 操作数类型冲突: int 与 time 不兼容
   at Microsoft.Data.SqlClient.SqlCommand.<>c.<ExecuteDbDataReaderAsync>b__188_0(Task`1 result)
   at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
   at FreeSql.Internal.CommonProvider.AdoProvider.ExecuteReaderMultipleAsync(Int32 multipleResult, DbConnection connection, DbTransaction transaction, Func`3 fetchHandler, Action`2 schemaHandler, CommandType cmdType, String cmdText, Int32 cmdTimeout, DbParameter[] cmdParms, CancellationToken cancellationToken)
ClientConnectionId:8f782a84-18ac-40b1-bed9-2071877a0c0a
Error Number:206,State:2,Class:16
   --- End of inner exception stack trace ---
   at FreeSql.Internal.CommonProvider.AdoProvider.LoggerException(IObjectPool`1 pool, PrepareCommandResult pc, Exception ex, DateTime dt, StringBuilder logtxt, Boolean isThrowException)
   at FreeSql.Internal.CommonProvider.AdoProvider.ExecuteReaderMultipleAsync(Int32 multipleResult, DbConnection connection, DbTransaction transaction, Func`3 fetchHandler, Action`2 schemaHandler, CommandType cmdType, String cmdText, Int32 cmdTimeout, DbParameter[] cmdParms, CancellationToken cancellationToken)
   at FreeSql.Internal.CommonProvider.AdoProvider.QueryAsync[T](Type resultType, DbConnection connection, DbTransaction transaction, CommandType cmdType, String cmdText, Int32 cmdTimeout, DbParameter[] cmdParms, CancellationToken cancellationToken)
   at FreeSql.SqlServer.Curd.SqlServerUpdate`1.<>c__DisplayClass8_0`1.<<RawExecuteUpdatedAsync>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at FreeSql.Internal.CommonProvider.UpdateProvider`1.ToSqlFetchAsync(Func`2 fetchAsync)
   at FreeSql.SqlServer.Curd.SqlServerUpdate`1.RawExecuteUpdatedAsync[TReturn](IEnumerable`1 columns, CancellationToken cancellationToken)
   at FreeSql.Internal.CommonProvider.UpdateProvider`1.<>c__DisplayClass67_0`1.<<SplitExecuteUpdatedAsync>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at FreeSql.Internal.CommonProvider.UpdateProvider`1.SplitExecuteAsync(Int32 valuesLimit, Int32 parameterLimit, String traceName, Func`1 executeAsync, CancellationToken cancellationToken)
   at FreeSql.Internal.CommonProvider.UpdateProvider`1.SplitExecuteUpdatedAsync[TReturn](Int32 valuesLimit, Int32 parameterLimit, IEnumerable`1 columns, CancellationToken cancellationToken)

生成错误SQL如下:

UPDATE [Test] SET [ActTime] = 36000

但是,只要换一种Set方式(即换作上方代码注释行),会生成正确的SQL执行成功。

数据库版本

SqlServer 2016

安装的Nuget包

3.2.820

.net framework/. net core? 及具体版本

.NET 8

LeaFrock commented 1 month ago

另外是否考虑支持TimeOnly也对应time类型?从语义上来说它比TimeSpan更合适,只是出来得晚了些。

2881099 commented 1 month ago

要考虑前后.net版本问题,暂时还没有兼容。

.Set(a.ActTime, newActTime) 这样解决

原因是前期考虑 TimeSpan 表达式树函数解析,把它转成了毫秒,所以在 lambda 表达式中使用它就解析成 long