我的系统是数据库优先,EF 4.3.1。
我有一个表,其中PK由两个int列和一个日期时间组成。 该表是一个“评论”表,用于保留评论..
CREATE TABLE [dbo].[ArticleComments]( [ArticleId] [int] NOT NULL, [UserId] [int] NOT NULL, [MessageText] [nvarchar](max) NOT NULL, [CreatedAt] [datetime] NOT NULL, [ExternalData] [bigint] NULL, CONSTRAINT [PK_ArticleComments] PRIMARY KEY CLUSTERED ( [ArticleId] ASC, [UserId] ASC, [CreatedAt] ASC ) )
在我的逻辑中,当创建注释时,我将ArticleComment对象发送到另一个线程,在该线程中打开另一个上下文以对该对象执行其他操作,最终可以保存该对象。
问题是,当稍后保存对象时,它有时会抛出一个没有保存任何内容的异常。
我打开了探查器,看看在SaveChanges()
exec sp_executesql N'update [dbo].[ArticleComments] set [ExternalData] = @0 where ((([ArticleId] = @1) and ([UserId] = @2)) and ([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。
仅供参考:in addition, datetime is rounded in SQL Server
所以,我找到了这篇文章:Round .NET DateTime milliseconds, so it can fit SQL Server milliseconds
这显示了将.net时间转换为SQL时间的好方法。我认为在框架中有一个类 Microsoft® System CLR Types for Microsoft® SQL Server® 2012在System.Data.SqlTypes
,名为SqlDateTime
也会这样做。
所以我的代码看起来像这样(使用刚才链接的SO答案的扩展名):
hack the time --> message.CreatedAt = message.CreatedAt.RoundToSqlServerDateTime(); db.ArticleComments.Attach(message); message.ExternalData = someNumber; db.SaveChanges();
它有效。
但所有这些都是黑客攻击,而不是解决方案。为什么EF在这里失败,我做错了什么?