I'm using EF Core with <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.2" />
I've just added a NodaTime.LocalDate
field to my entity which uses a package called NodaTime:
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL.NodaTime" Version="5.0.2" />
The field:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Nest;
namespace Vepo.Domain
{
[ElasticsearchType(RelationName = "eventitem", IdProperty = "Id")]
public class EventItem : VeganItem<EventItemEstablishment>
{
[MaxLength(10)]
public List<NpgsqlRange<LocalDateTime>> Dates { get; set; }
}
}
and I now get this error:
InvalidOperationException: The property ‘EventItem.Dates’ could not be mapped, because it is of type
List<NpgsqlRange<LocalDateTime>>
which is not a supported primitive type or a valid entity type. Either explicitly map this property, or ignore it using the ‘[NotMapped]’ attribute or by using ‘EntityTypeBuilder.Ignore’ in ‘OnModelCreating’.
So Ef Core cannot map List<NpgsqlRange>.
This is a demo of how to let EF Core map LocalDateTime
by using a value converter:
base.OnModelCreating(modelBuilder);
var localDateConverter =
new ValueConverter<LocalDate, DateTime>(v =>
v.ToDateTimeUnspecified(),
v => LocalDate.FromDateTime(v));
modelBuilder.Entity<Event>()
.Property(e => e.Date)
.HasConversion(localDateConverter);
But this does not work for me because my field is not LocalDateTime
, it is List<NpgsqlRange<LocalDateTime>>
I am struggling to create the value converter correctly. Any help appreciated.
FYI My front end is sending a list of custom objects to the back end: [{DateTime startDate, DateTime endDate}]
IMPORTANT: Shay Rojansky's version is working for me, I needed to change my Startup.cs
code from this:
public void ConfigureServices(IServiceCollection services)
{
services
.AddDbContext<VepoContext>(opt => {
opt
.UseNpgsql(
Configuration
.GetConnectionString("DefaultConnection"))
.EnableSensitiveDataLogging()
.EnableDetailedErrors()
.LogTo(Console.WriteLine);
});
NpgsqlConnection.GlobalTypeMapper.UseNodaTime();
To this (basically to his - but my initialising code was using ConfigureServices
, not OnConfiguring
so I thought I will post his solution with the ConfigureServices
syntax here for people who's code is already using ConfigureServices
:
services
.AddDbContext<VepoContext>(opt => {
opt
.UseNpgsql(
Configuration
.GetConnectionString("DefaultConnection"),
o => o.UseNodaTime()
)
.EnableSensitiveDataLogging()
.EnableDetailedErrors()
.LogTo(Console.WriteLine);
});
CodePudding user response:
The above works for me as-is using 5.0.10, without a value converter:
await using var ctx = new BlogContext();
await ctx.Database.EnsureDeletedAsync();
await ctx.Database.EnsureCreatedAsync();
public class BlogContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseNpgsql(@"Host=localhost;Username=test;Password=test", o => o.UseNodaTime())
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}
public class Blog
{
public int Id { get; set; }
public List<NpgsqlRange<LocalDateTime>> Dates { get; set; }
}
The following table gets created:
CREATE TABLE "Blogs" (
"Id" integer GENERATED BY DEFAULT AS IDENTITY,
"Dates" tsrange[] NULL,
CONSTRAINT "PK_Blogs" PRIMARY KEY ("Id")
);
You may be interested in the new multirange type in the upcoming PostgreSQL 14 release. Support for it has already been added to version 6.0 of the EF Core provider (a release candidate is already out for both PG14 and EF Core 6.0.0), so you may want to give them a try.