Error when setting column attributes
Not sure how to explain the issue, but I can demonstrate two scenarios where it works with one but not the other, so here it goes (or check the repro repo:
Scenario 1
If we create a table like the following (note that column names are PascalCase):
CREATE TABLE IF NOT EXISTS public."GenericTable1"
(
"Id" bigint NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
"TypeId" bigint,
"Content" text COLLATE pg_catalog."default",
CONSTRAINT generic_table1_pkey PRIMARY KEY ("Id")
)
And have a bit of code like the following
public class MyDbContext1 : DbContext
{
public DbSet<GenericTable1> T1 { get; set; }
public DbSet<GenericTable1<GenericTableData1>> T2 { get; set; }
public DbSet<GenericTable1<GenericTableData2>> T3 { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseNpgsql("Server=localhost;Port=5432;Database=testdb;User Id=postgres;Password=123456");
base.OnConfiguring(optionsBuilder);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<GenericTable1>().HasKey(x => x.Id);
modelBuilder.Entity<GenericTable1>().HasDiscriminator(x => x.TypeId).HasValue(-1);
modelBuilder.Entity<GenericTable1<GenericTableData1>>().HasDiscriminator(x => x.TypeId).HasValue(1);
modelBuilder.Entity<GenericTable1<GenericTableData2>>().HasDiscriminator(x => x.TypeId).HasValue(2);
modelBuilder.Entity<GenericTable1<GenericTableData1>>().Property(x => x.Content).HasColumnType("jsonb");
modelBuilder.Entity<GenericTable1<GenericTableData2>>().Property(x => x.Content).HasColumnType("jsonb");
base.OnModelCreating(modelBuilder);
}
}
[Table("GenericTable1")]
public class GenericTable1
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
public long TypeId { get; set; }
}
public class GenericTable1<T> : GenericTable1
{
public T Content { get; set; }
}
And to run the above, works fine without any issues:
//this works
using (var context = new MyDbContext1())
{
var data = context.T2.Where(x => x.Id > 0).ToList();
}
Scenario 2
Now if we create another table, pretty much the same as before (note that column names are snake_case):
CREATE TABLE IF NOT EXISTS public.generic_table2
(
id bigint NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
type_id bigint,
content text COLLATE pg_catalog."default",
CONSTRAINT generic_table2_pkey PRIMARY KEY (id)
)
And the code (note the 'Column' attributes:
public class MyDbContext2 : DbContext
{
public DbSet<GenericTable2> T1 { get; set; }
public DbSet<GenericTable2<GenericTableData1>> T2 { get; set; }
public DbSet<GenericTable2<GenericTableData2>> T3 { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseNpgsql("Server=localhost;Port=5432;Database=testdb;User Id=postgres;Password=123456");
base.OnConfiguring(optionsBuilder);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<GenericTable2>().HasKey(x => x.Id);
modelBuilder.Entity<GenericTable2>().HasDiscriminator(x => x.TypeId).HasValue(-1);
modelBuilder.Entity<GenericTable2<GenericTableData1>>().HasDiscriminator(x => x.TypeId).HasValue(1);
modelBuilder.Entity<GenericTable2<GenericTableData2>>().HasDiscriminator(x => x.TypeId).HasValue(2);
modelBuilder.Entity<GenericTable2<GenericTableData1>>().Property(x => x.Content).HasColumnType("jsonb");
modelBuilder.Entity<GenericTable2<GenericTableData2>>().Property(x => x.Content).HasColumnType("jsonb");
base.OnModelCreating(modelBuilder);
}
}
[Table("generic_table2")]
public class GenericTable2
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column("id")]
public long Id { get; set; }
[Column("type_id")]
public long TypeId { get; set; }
}
public class GenericTable2<T> : GenericTable2
{
[Column("content")]
public T Content { get; set; }
}
And to run it:
//this doesn't work
using (var context = new MyDbContext2())
{
var data = context.T2.Where(x => x.Id > 0).ToList();
}
It throws:
'GenericTable2<GenericTableData1>.Content' and 'GenericTable2<GenericTableData2>.Content' are both mapped to column 'content' in 'generic_table', but are configured to use differing provider types ('GenericTableData1' and 'GenericTableData2').
Stack trace
at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.ValidateCompatible(IProperty property, IProperty duplicateProperty, String columnName, StoreObjectIdentifier& storeObject, IDiagnosticsLogger`1 logger)
at Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal.NpgsqlModelValidator.ValidateCompatible(IProperty property, IProperty duplicateProperty, String columnName, StoreObjectIdentifier& storeObject, IDiagnosticsLogger`1 logger)
at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.ValidateSharedColumnsCompatibility(IReadOnlyList`1 mappedTypes, StoreObjectIdentifier& storeObject, IDiagnosticsLogger`1 logger)
at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.ValidateSharedTableCompatibility(IModel model, IDiagnosticsLogger`1 logger)
at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
at Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal.NpgsqlModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelRuntimeInitializer.Initialize(IModel model, Boolean designTime, IDiagnosticsLogger`1 validationLogger)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, ModelCreationDependencies modelCreationDependencies, Boolean designTime)
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel(Boolean designTime)
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__8_4(IServiceProvider p)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass2_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
at Microsoft.EntityFrameworkCore.DbContext.get_ContextServices()
at Microsoft.EntityFrameworkCore.DbContext.get_Model()
at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityType()
at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.CheckState()
at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityQueryable()
at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.System.Linq.IQueryable.get_Provider()
at System.Linq.Queryable.Where[TSource](IQueryable`1 source, Expression`1 predicate)
at EfTest.Program.Main(String[] args) in C:\Users\rebin\source\repos\EfTest\EfTest\Program.cs:line 16
Repro repo:
https://github.com/r-work/EfTest
Include provider and version information
EF Core version: 7.0.2 Database provider: Npgsql.EntityFrameworkCore.PostgreSQL v7.0.1 Target framework: .NET 7.0 Operating system: Windows 11 22H2 (22621.1105) IDE: Visual Studio 2022 17.5 Preview 3.0
This works if I downgrade to EntityFrameworkCore 6.0.13 and PostgreSQL 6.0.8
Scenario 2 in OnModelCreating add:
modelBuilder.Entity<GenericTable2>().ToTable("generic_table2"); modelBuilder.Entity<GenericTable2>().Property(p => p.Id).HasColumnName("id"); modelBuilder.Entity<GenericTable2>().Property(p => p.TypeId).HasColumnName("type_id");
Scenario 2 in OnModelCreating add:
modelBuilder.Entity<GenericTable2>().ToTable("generic_table2"); modelBuilder.Entity<GenericTable2>().Property(p => p.Id).HasColumnName("id"); modelBuilder.Entity<GenericTable2>().Property(p => p.TypeId).HasColumnName("type_id");
Done that, throws the same exception.
Probably a duplicate of #29859.
/cc @AndriySvyryd @roji