Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<Content Include="..\DateOnlyAndTimeOnlyTypes\appsettings.json" Link="appsettings.json" />
<ItemGroup>
<Content Include="..\DateOnlyAndTimeOnlyTypes\appsettings.json" Link="appsettings.json" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.0">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.11.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.13" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.13">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0">
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.13" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.0.13" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.13">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.13" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.13" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="4.0.1">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.0">
<PackageReference Include="coverlet.collector" Version="10.1.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,90 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using System;
using System.Linq;
using Xunit;

namespace DateOnlyAndTimeOnlyTypes.Tests;

public class DateOnlyAndTimeOnlyTypesTest
{
private readonly AppDbContext _context;

public DateOnlyAndTimeOnlyTypesTest()
private static AppDbContext CreateSqlServerContext()
{
var contextOptions = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase("DateOnlyDemo")
.ConfigureWarnings(b => b.Ignore(InMemoryEventId.TransactionIgnoredWarning))
// No connection is opened: these tests only build the model and generate SQL.
var options = new DbContextOptionsBuilder<AppDbContext>()
.UseSqlServer("Server=.;Database=DateOnlyDemo;Trusted_Connection=True;TrustServerCertificate=True")
.Options;

_context = new AppDbContext(contextOptions);
_context.Database.EnsureDeleted();
_context.Database.EnsureCreated();
return new AppDbContext(options);
}

[Fact]
public void GivenDbContext_WhenHavingProperConverters_ThenRightlyStoresDateOnlyTimeOnlyValues()
public void GivenDbContext_WhenSavingDateOnlyTimeOnlyValues_ThenReadsThemBack()
{
var employee = new Employee
{
Name = "John Doe",
BirthDate = new DateOnly(2023, 5, 9),
WorkStartTime = new TimeOnly(8, 30),
WorkEndTime = new TimeOnly(4, 30)
var contextOptions = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase("DateOnlyDemo")
.ConfigureWarnings(b => b.Ignore(InMemoryEventId.TransactionIgnoredWarning))
.Options;

using var context = new AppDbContext(contextOptions);
context.Database.EnsureDeleted();
context.Database.EnsureCreated();

var employee = new Employee
{
Name = "John Doe",
BirthDate = new DateOnly(2023, 5, 9),
WorkStartTime = new TimeOnly(8, 30),
WorkEndTime = new TimeOnly(16, 30)
};

_context.Employees.Add(employee);
_context.SaveChanges();
context.Employees.Add(employee);
context.SaveChanges();

var storedEmployee = _context.Employees.Find(employee.Id);
var storedEmployee = context.Employees.Find(employee.Id);

Assert.NotNull(storedEmployee);
Assert.Equal(employee.BirthDate, storedEmployee!.BirthDate);
Assert.Equal(employee.WorkStartTime, storedEmployee.WorkStartTime);
Assert.Equal(employee.WorkEndTime, storedEmployee.WorkEndTime);
}
}

[Fact]
public void GivenSqlServerProvider_WhenGeneratingSchema_ThenMapsDateOnlyToDateAndTimeOnlyToTime()
{
using var context = CreateSqlServerContext();

var script = context.Database.GenerateCreateScript();

Assert.Contains("[BirthDate] date NOT NULL", script);
Assert.Contains("[WorkStartTime] time NOT NULL", script);
Assert.Contains("[WorkEndTime] time NOT NULL", script);
}

[Fact]
public void GivenDateOnlyMember_WhenFiltering_ThenTranslatesToSql()
{
using var context = CreateSqlServerContext();

var sql = context.Employees
.Where(e => e.BirthDate.Year == 1990 && e.WorkStartTime.Hour < 9)
.ToQueryString();

Assert.Contains("DATEPART(year, [e].[BirthDate]) = 1990", sql);
Assert.Contains("DATEPART(hour, [e].[WorkStartTime]) < 9", sql);
}

[Fact]
public void GivenLegacyDatetime2Column_WhenUsingConverter_ThenKeepsDatetime2()
{
var options = new DbContextOptionsBuilder<LegacyAppDbContext>()
.UseSqlServer("Server=.;Database=LegacyDemo;Trusted_Connection=True;TrustServerCertificate=True")
.Options;

using var context = new LegacyAppDbContext(options);

var script = context.Database.GenerateCreateScript();

Assert.Contains("[BirthDate] datetime2 NOT NULL", script);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using Microsoft.EntityFrameworkCore;

namespace DateOnlyAndTimeOnlyTypes.Tests;

// An existing database keeps BirthDate in a datetime2 column that we can't change.
public class LegacyAppDbContext(DbContextOptions<LegacyAppDbContext> options) : DbContext(options)
{
public DbSet<Employee> Employees => Set<Employee>();

protected override void ConfigureConventions(ModelConfigurationBuilder builder)
{
base.ConfigureConventions(builder);

builder.Properties<DateOnly>()
.HaveConversion<DateOnlyConverter>()
.HaveColumnType("datetime2");
}
}
Original file line number Diff line number Diff line change
@@ -1,34 +1,24 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

namespace DateOnlyAndTimeOnlyTypes;

public class AppDbContext : DbContext
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
namespace DateOnlyAndTimeOnlyTypes;
public class AppDbContext : DbContext
{
public DbSet<Employee> Employees => Set<Employee>();

protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
if (builder.IsConfigured)
return;

var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
builder.UseSqlServer(configuration.GetConnectionString("Default"));
}

protected override void ConfigureConventions(ModelConfigurationBuilder builder)
public DbSet<Employee> Employees => Set<Employee>();

protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
base.ConfigureConventions(builder);
if (builder.IsConfigured)
return;

var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
builder.UseSqlServer(configuration.GetConnectionString("Default"));
}

builder.Properties<DateOnly>()
.HaveConversion<DateOnlyConverter, DateOnlyComparer>()
.HaveColumnType("date");
public AppDbContext() { }

builder.Properties<TimeOnly>()
.HaveConversion<TimeOnlyConverter, TimeOnlyComparer>();
}

public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
}
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,35 @@

<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.0">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.13" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.13">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0">
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.13" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.13">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.13" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.13" />
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="10.0.13" />
</ItemGroup>

<ItemGroup>
<Folder Include="Migrations\" />
<ItemGroup>
<Folder Include="Migrations\" />
</ItemGroup>

<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace DateOnlyAndTimeOnlyTypes.Migrations
{
/// <inheritdoc />
public partial class RemoveDateOnlyTimeOnlyConverters : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{

}

/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{

}
}
}
Loading
Loading