我的系统首先是数据库,EF 4.3.1。
我有一个表,其中 PK 由两个 int 列和一个日期时间组成。该表是一个“评论”表,用于保留评论。
创建表 [dbo].[ArticleComments]( [ArticleId] [int] 非空, [用户 ID] [int] 非空, [MessageText] [nvarchar](max) NOT NULL, [CreatedAt] [datetime] 非空, [外部数据] [bigint] NULL, 约束 [PK_ArticleComments] 主键集群 ( [文章编号] ASC, [用户 ID] ASC, [创建时间] ASC ) )
在我的逻辑中,当创建评论时,我将 ArticleComment 对象发送到另一个线程,在该线程中打开另一个上下文以对对象执行其他操作,最终可以在其中保存对象。
问题是,当对象稍后被保存时,它有时会抛出一个没有保存的异常。
我打开探查器查看执行的 SQLSaveChanges()
exec sp_executesql N'update [dbo].[ArticleComments] 设置 [外部数据] = @0 其中 ((([ArticleId] = @1) 和 ([UserId] = @2)) 和 ([CreatedAt] = @3)) ',N'@0 bigint,@1 int,@2 int,@3 datetime2(7)',@0=3243423,@1=6931,@2=2,@3='2012-10-11 11: 23:25.4734801'
并发现问题在于 EF 将其映射到 datetime2(7) 以代替常规日期时间,这就是为什么此更新不会更改任何内容并引发异常的原因。
我检查了 EDMX 文件,那里说类型是日期时间,精度为 3。
仅供参考:此外,日期时间在 SQL Server 中四舍五入
所以,我发现这篇文章:Round .NET DateTime milliseconds, so it can fit SQL Server milliseconds
这显示了将 .net 时间四舍五入到 SQL 时间的好方法。我认为在Microsoft® SQL Server® 2012的Microsoft® System CLR Types框架 中有一个类可以做同样的事情。System.Data.SqlTypes
SqlDateTime
所以我的代码看起来像这样(使用刚刚链接的 SO 答案的扩展名):
破解时间 --> message.CreatedAt = message.CreatedAt.RoundToSqlServerDateTime(); db.ArticleComments.Attach(消息); message.ExternalData = someNumber; db.SaveChanges();
它有效。
但所有这些都是技巧,而不是解决方案。为什么 EF 在这里失败,我做错了什么?