My system is database first, EF 4.3.1.
I have a table in which the PK is composed of two int columns and a datetime. The table is a 'comment' table, to keep comments..
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 ) )
In my logic, when a comment is created, I send the ArticleComment object to another thread, where another context is opened to do additional actions on the object, in which eventually the object may be saved.
The problem is, when the object is later saved, it sometimes throws an exception that nothing was saved.
I opened the profiler to see what SQL is executed on 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'
And found out that the problem is that EF was mapping it to a datetime2(7) in stand of regular datetime, which is why this update will not change anything and the exception is thrown.
I checked the EDMX file, over there it says the type is datetime with precision 3.
FYI: in addition, datetime is rounded in SQL Server
SO, i found this article: Round .NET DateTime milliseconds, so it can fit SQL Server milliseconds
Which shows a nice way to round .net time to SQL time. And I think there is a class for this in the framework Microsoft® System CLR Types for Microsoft® SQL Server® 2012 at System.Data.SqlTypes
called SqlDateTime
that will do the same.
So my code looks like this (using the extension from the SO answer just linked):
hack the time --> message.CreatedAt = message.CreatedAt.RoundToSqlServerDateTime(); db.ArticleComments.Attach(message); message.ExternalData = someNumber; db.SaveChanges();
And it works.
But all of these are hacks, not solutions. Why is EF failing here, what am I doing incorrectly?