Native DateOnly and TimeOnly support in Entity Framework 8 in SQL Server

.NET 6 brought us two new datatypes: DateOnly and TimeOnly. For those types we don't have any first class support in Entity Framework - until now.

There is a recent change, that hit us with Entity Framework 8 that might ease the situation and brings native support for those types.

DateOnly and TimeOnly

I guess those types are pretty self-explanatory. Until .NET 6, if you wanted to represent someone's birthday you had to include the time information as well, as this is just how DateTime works. But maybe the date part is enough for our use case. So DateOnly would be sufficient. And the good thing is, that DateOnly has no time zone information, which makes handling those kinds of information easier.

TimeOnly is the same but we instead of the date portion we take the time portion (independent of the date). All in all DateOnly and TimeOnly are a nice way of decoupling this information from DateTime.

The problem with that was that those new types were not natively understandable/translateable by Entity Framework, especially with the SQL Server.

Mapping the types

To make this work, you had to define a custom (even though) simple converter or use a NuGet package, that did the same:

public class DateOnlyConverter : ValueConverter<DateOnly, DateTime>
{
    public DateOnlyConverter() : base(
            dateOnly => dateOnly.ToDateTime(TimeOnly.MinValue),
            dateTime => DateOnly.FromDateTime(dateTime))
    {
    }
}

public class DateOnlyComparer : ValueComparer<DateOnly>
{
    public DateOnlyComparer() : base(
        (d1, d2) => d1.DayNumber == d2.DayNumber,
        d => d.GetHashCode())
    {
    }
}

That then can be used in your DbContext:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<MyEntity>(builder =>
    {
        builder.Property(x => x.Date)
            .HasConversion<DateOnlyConverter, DateOnlyComparer>();
    });
}

The same applies to TimeOnly respectively. And this seems odd given the fact that there are data types in SQL Serve that can represent that information perfectly.

Entity Framework 8

There was a recent Pull Request merged that enables you to use DateOnly and TimeOnly without any additional mapping logic. A small disclaimer here: The issue is flagged as "consider-for-next-release" which can indicate that this feature will not make it into Entity Framework 8, but I do think that it is very likely to land in the next release.

Just for the sake of completeness: Sqlite did already receive that functionality with .NET 6.

Resources

1
An error has occurred. This application may no longer respond until reloaded. Reload x