Home > Mobile >  EF Core NodaTime field - could not be mapped
EF Core NodaTime field - could not be mapped

Time:10-02

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.

  • Related