EF Core and DateOnly
Solving some problems.
This isn鈥檛 going to be a long post. I just wanted to write this stuff down somewhere and this is as good of a place as any.
I鈥檝e been using .NET 6 and EF Core 6 on a project for work. It鈥檚 been great so far, but I鈥檝e wanted to use the new DateOnly
type that was added in .NET 6 with EF Core. It seemed like a good fit to map to the date
type in SQL. Unfortunately, this doesn鈥檛 really work out of the box. Here鈥檚 how I got it all working.
Configuring the Context
DateOnly
doesn鈥檛 map to date
by default. I鈥檓 sure EF 7 or later will fix this, but it requires a bit of configuring in EF Core 6. First you need a converter to convert DateOnly
to and from DateTime
. This is pretty simple:
internal class DateOnlyConverter : ValueConverter<DateOnly, DateTime>
{
public DateOnlyConverter()
: base(d => d.ToDateTime(TimeOnly.MinValue),
d => DateOnly.FromDateTime(d))
{ }
}
Then you need to tell EF Core to both use that converter for DateOnly
properties and to store those properties as date
columns in the database. This, also, is not too complex. In your context class, the one that inherits from DbContext
, override ConfigureConventions
like so:
protected override void ConfigureConventions(ModelConfigurationBuilder builder)
{
// Store DateOnly values as 'date' columns
builder.Properties<DateOnly>()
.HaveConversion<DateOnlyConverter>()
.HaveColumnType("date");
// Any other "global" model configurations go here
}
After that, DateOnly
properties work like you would expect. 馃帀
Change Tracking
Of course, it works until it doesn鈥檛. And this is what I ran into today that caused me to write this post.
EF Core has change tracking built in. It knows what entities are retrieved from the database and can tell when they have been modified so it can efficiently write them back to the database. It鈥檚 really good, except DateOnly
properties don鈥檛 quite work with it.
Basically, if you have an entity with a DateOnly
property, changing only the DateOnly
property does not get noticed by the change tracker. Changing other properties at the same time as the DateOnly
property will make it work fine, but sometimes that鈥檚 not what you need to do. This is very annoying but thankfully EF core has a way to manually let it know that an entity has changed:
_dbContext.Entry(entity).State = EntityState.Modified;
This frustrated me for an hour this morning, so I hope my 15 minute blog post can help someone else avoid the same frustration.