
EF Core and DateOnly
Solving some problems.
This isn’t 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’ve been using .NET 6 and EF Core 6 on a project for work. It’s been great so far, but I’ve 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’t really work out of the box. Here’s how I got it all working.
Configuring the Context
DateOnly
doesn’t map to date
by default. I’m 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> |
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) |
After that, DateOnly
properties work like you would expect. 🎉
Change Tracking
Of course, it works until it doesn’t. 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’s really good, except DateOnly
properties don’t 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’s 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.