Is it possible to have Entity Framework (I am using the Code First Approach with CTP5 currently) store all DateTime values as UTC in the database?
Or is there maybe a way to specify it in the mapping, for example in this one for the last_login column:
modelBuilder.Entity<User>().Property(x => x.Id).HasColumnName("id");
modelBuilder.Entity<User>().Property(x => x.IsAdmin).HasColumnName("admin");
modelBuilder.Entity<User>().Property(x => x.IsEnabled).HasColumnName("enabled");
modelBuilder.Entity<User>().Property(x => x.PasswordHash).HasColumnName("password_hash");
modelBuilder.Entity<User>().Property(x => x.LastLogin).HasColumnName("last_login");
If you are careful to properly pass in UTC dates when you set the values and all you care about is making sure the DateTimeKind is set properly when the entities are retrieved from the database, see my answer here: https://stackoverflow.com/a/9386364/279590
For those who need to achieve @MattJohnson solution with .net framework 4 like me, with reflection syntax/method limitation , it require a little bit modification as listed below:
I'm researching this right now, and most of these answers aren't exactly great. From what I can see, there's no way to tell EF6 that the dates coming out of the database are in UTC format. If that is the case, the simplest way to make sure your model's DateTime properties are in UTC would be to verify and convert in the setter.
Here's some c# like pseudocode which describes the algorithm
The first two branches are obvious. The last holds the secret sauce.
When EF6 creates a model from data loaded from the database, DateTimes are
DateTimeKind.Unspecified
. If you know your dates are all UTC in the db, then the last branch will work great for you.DateTime.Now
is alwaysDateTimeKind.Local
, so the above algorithm works fine for dates generated in code. Most of the time.You have to be cautious, however, as there are other ways
DateTimeKind.Unspecified
can sneak into your code. For example, you might deserialize your models from JSON data, and your deserializer flavor defaults to this kind. It's up to you to guard against localized dates markedDateTimeKind.Unknown
from getting to that setter from anybody but EF.The accepted answer does not work for Projected or Anonymous object. Performance could be a problem too.
To achieve this, we need to use a
DbCommandInterceptor
, an object provided by EntityFramework.Create Interceptor:
interceptionContext.Result
is DbDataReader, which we replace by oursRegister the interceptor in your
DbConfiguration
Finally, register the configuration for on your
DbContext
That's it. Cheers.
For simplicity, here is the entire implementation of DbReader:
There is no way to specify the DataTimeKind in the Entity Framework. You may decide to convert the date time values to utc before storing to db and always assume the data retrived from db as UTC. But the DateTime objects materalized during query will always be "Unspecified". You could also evalualte using DateTimeOffset object instead of DateTime.
In my case, I had only one table with UTC datetimes. Here's what I did: