efcore.pg: Can't map user-defined range with subtype StoreType when the subtype type is plugin-provided

I’ve attempted to use the new custom range type support with LocalTime (from NodaTime).

So I’ve set it up with:

            services.AddDbContext<MainContext>(options => 
                options.UseNpgsql(
                    Configuration.GetConnectionString("MainContext"),
                    opts => 
                    {
                        opts.UseNodaTime();
                        opts.MapRange<LocalTime>("timerange");
                    }));

and:

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.ForNpgsqlHasRange("timerange", "time");
            // ...
        }

Then in one of my model classes I’ve put:

public NpgsqlRange<LocalTime> Period { get; set; }

Then I ran:

dotnet ef migrations add Initial

and I get:

System.TypeLoadException: Could not load type 'Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping.NpgsqlRangeTypeMapping`1' from assembly 'Npgsql.EntityFrameworkCore.PostgreSQL, Version=2.2.0.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7'.
   at Npgsql.EntityFrameworkCore.PostgreSQL.NodaTime.NodaTimePlugin..ctor()
   at Microsoft.EntityFrameworkCore.NodaTimeDbContextOptionsExtensions.UseNodaTime(NpgsqlDbContextOptionsBuilder optionsBuilder) in /home/roji/projects/EFCore.PG/src/EFCore.PG.NodaTime/NodaTimeDbContextOptionsExtensions.cs:line 20
   at Server.Startup.<>c.<ConfigureServices>b__4_2(NpgsqlDbContextOptionsBuilder opts)

These are the versions I’m using:

    <PackageReference Include="NodaTime" Version="2.3.0" />
    <PackageReference Include="Npgsql" Version="4.0.3" />
    <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="2.2.0-preview1" />
    <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL.NodaTime" Version="2.1.1" />

What am I doing wrong?

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 15 (10 by maintainers)

Commits related to this issue

Most upvoted comments

@austindrenski OK, I took a look and your analysis seems correct… The user-defined range mapping setup process involves looking at NpgsqlTypeMappingSource’s ClrTypeMapping dictionary, but that dictionary only includes the built-in mappings, and not the plugins.

I think the right way would be to move the user-defined range logic out of the constructor and into FindMapping(), probably by adding an additional FindUserDefinedRangeMapping() which gets called, just like FindArrayMapping(). Like FindArrayMapping(), if a mapping is instantiated, we can update NpgsqlTypeMappingSource’s ClrTypeMapping and StoreTypeMapping dictionaries so that the next lookup simply finds it via FindExistingMapping(). Also, when looking for the subtype we definitely should not look at ClrTypeMapping, but rather recursively call FindMapping() which would include the plugins (again, exactly like FindArrayMapping() already does).

Are you interested in fixing this? If not I can probably do this quite quickly.

@Jefffrey Yes, that’s the exception I referenced above.

@austindrenski I run a dotnet clean && dotnet restore yes, and nothing changed.

I think you can reproduce the issue by creating a new dotnet project and just define a model with a range for LocalTime following the first post.