Skip to content

Commit

Permalink
Breaking change note for DateOnly/TimeOnly scaffolding
Browse files Browse the repository at this point in the history
Closes #4233
  • Loading branch information
roji committed Jan 30, 2023
1 parent 222479a commit f87cdce
Showing 1 changed file with 51 additions and 0 deletions.
51 changes: 51 additions & 0 deletions entity-framework/core/what-is-new/ef-core-8.0/breaking-changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,54 @@ uid: core/what-is-new/ef-core-8.0/breaking-changes
# Breaking changes in EF Core 8.0 (EF8)

This page will dcoument API and behavior changes that have the potential to break existing applications updating to EF Core 8.0.

## Summary

| **Breaking change** | **Impact** |
|:---------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| [SQL Server `date` and `time` now scaffold to .NET `DateOnly` and `TimeOnly`](#sqlserver-date-time-only) | Medium |

## Medium-impact changes

<a name="sqlserver-date-time-only"></a>

### SQL Server `date` and `time` now scaffold to .NET `DateOnly` and `TimeOnly`

[Tracking Issue #24507](https://github.com/dotnet/efcore/issues/24507)

#### Old behavior

Previously, when scaffolding a SQL Server database with `date` or `time` columns, EF would generate entity properties with types [`DateTime`](https://learn.microsoft.com/dotnet/api/system.datetime) and [`TimeSpan`](https://learn.microsoft.com/dotnet/api/system.timespan).

#### New behavior

Starting with EF Core 8.0, `date` and `time` are scaffolded as [`DateOnly`](https://learn.microsoft.com/dotnet/api/system.dateonly) and [`TimeOnly`](https://learn.microsoft.com/dotnet/api/system.timeonly).

#### Why

`DateOnly` and `TimeOnly` were introduced in .NET 6.0, and are a perfect match for mapping the database date and time types. `DateTime` notably contains a time component that goes unused and can cause confusion when mapping it to `date`, and `TimeSpan` represents a time interval - possibly including days - rather than a time of day at which an event occurs. Using the new types prevents bugs and confusion, and provides clarity of intent.

#### Mitigations

This change only affects users which regularly re-scaffold their database into an EF code model ("database-first" flow).

It is recommended to react to this change by modifying your code to use the newly scaffolded `DateOnly` and `TimeOnly` types. However, if that isn't possible, you can edit the scaffolding templates to revert to the previous mapping. To do this, set up the templates as described on [this page](xref:core/managing-schemas/scaffolding/templates). Then, edit the `EntityType.t4` file, find where the entity properties get generated (search for `property.ClrType`), and change the code to the following:

```c#
var clrType = property.GetColumnType() switch
{
"date" when property.ClrType == typeof(DateOnly) => typeof(DateTime),
"date" when property.ClrType == typeof(DateOnly?) => typeof(DateTime?),
"time" when property.ClrType == typeof(TimeOnly) => typeof(TimeSpan),
"time" when property.ClrType == typeof(TimeOnly?) => typeof(TimeSpan?),
_ => property.ClrType
};

usings.AddRange(code.GetRequiredUsings(clrType));

var needsNullable = Options.UseNullableReferenceTypes && property.IsNullable && !clrType.IsValueType;
var needsInitializer = Options.UseNullableReferenceTypes && !property.IsNullable && !clrType.IsValueType;
#>
public <#= code.Reference(clrType) #><#= needsNullable ? "?" : "" #> <#= property.Name #> { get; set; }<#= needsInitializer ? " = null!;" : "" #>
<#
```

0 comments on commit f87cdce

Please sign in to comment.