当PK是基于日期时间时重新附加对象

时间:2012-10-11 13:10:43

标签: entity-framework entity-framework-4

我的系统是数据库优先,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()

上执行了什么SQL
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® 2012System.Data.SqlTypes,名为SqlDateTime也会这样做。

所以我的代码看起来像这样(使用刚才链接的SO答案的扩展名):

 hack the time -->  message.CreatedAt = message.CreatedAt.RoundToSqlServerDateTime();
                    db.ArticleComments.Attach(message);
                    message.ExternalData = someNumber;
                    db.SaveChanges();

它有效。

但所有这些都是黑客攻击,而不是解决方案。为什么EF在这里失败,我做错了什么?

0 个答案:

没有答案