dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.65k stars 3.15k forks source link

TPT + JSON column throws: The exception Entity type references entities mapped to JSON but is not itself mapped to a table or a view #32129

Closed MoienTajik closed 10 months ago

MoienTajik commented 10 months ago

Let's keep it simple:

public abstract class Journey
{
    public int Id { get; set; } = default!;

    public IEnumerable<ContentOrder> ContentOrders { get; private set; } = new List<ContentOrder>();
}

public sealed class Course : Journey
{
}

public sealed class Module : Journey
{
}

public sealed class CertificateProgram : Journey
{
}

public class ContentOrder(int contentId, string contentType)
{
    public int ContentId { get; private set; } = contentId;

    public string ContentType { get; private set; } = contentType;
}

internal sealed class JourneyConfiguration : IEntityTypeConfiguration<Journey>
{
    public void Configure(EntityTypeBuilder<Journey> builder)
    {
        builder.UseTpcMappingStrategy();
        builder.OwnsMany(journey => journey.ContentOrders, navBuilder => navBuilder.ToJson());
    }
}

Include stack traces

When I try to create a new migration for these entities, I get this error:

Unable to create a 'DbContext' of type 'LmsDbContext'. The exception 'Entity type 'Journey' references entities mapped to JSON but is not itself mapped to a table or a view. This is not supported.' was thrown while attempting to create an instance. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728

Include verbose output

dotnet ef migrations add "Add_Journeys" --startup-project src/LMS.API --project src/LMS.Infrastructure -o Data/Migrations --context LmsDbContext --verbose
...
Using project '/Users/moientajik/LMS/LMS.Service/src/LMS.Infrastructure/LMS.Infrastructure.csproj'.
Using startup project '/Users/moientajik/LMS/LMS.Service/src/LMS.API/LMS.API.csproj'.
Writing '/Users/moientajik/LMS/LMS.Service/src/LMS.Infrastructure/obj/LMS.Infrastructure.csproj.EntityFrameworkCore.targets'...
dotnet msbuild /target:GetEFProjectMetadata /property:EFProjectMetadataFile=/var/folders/41/1scblbfs6713lpd4v_80d7th0000gn/T/tmp2QkLmr.tmp /verbosity:quiet /nologo /Users/moientajik/LMS/LMS.Service/src/LMS.Infrastructure/LMS.Infrastructure.csproj
Writing '/Users/moientajik/LMS/LMS.Service/src/LMS.API/obj/LMS.API.csproj.EntityFrameworkCore.targets'...
dotnet msbuild /target:GetEFProjectMetadata /property:EFProjectMetadataFile=/var/folders/41/1scblbfs6713lpd4v_80d7th0000gn/T/tmp5pdxW4.tmp /verbosity:quiet /nologo /Users/moientajik/LMS/LMS.Service/src/LMS.API/LMS.API.csproj
Build started...
dotnet build /Users/moientajik/LMS/LMS.Service/src/LMS.API/LMS.API.csproj /verbosity:quiet /nologo /p:PublishAot=false

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:01.44
Build succeeded.
dotnet exec --depsfile /Users/moientajik/LMS/LMS.Service/src/LMS.API/bin/Debug/net8.0/LMS.API.deps.json --additionalprobingpath /Users/moientajik/.nuget/packages --runtimeconfig /Users/moientajik/LMS/LMS.Service/src/LMS.API/bin/Debug/net8.0/LMS.API.runtimeconfig.json /Users/moientajik/.dotnet/tools/.store/dotnet-ef/8.0.0-preview.7.23375.4/dotnet-ef/8.0.0-preview.7.23375.4/tools/net8.0/any/tools/netcoreapp2.0/any/ef.dll migrations add Add_Journeys -o Data/Migrations --context LmsDbContext --assembly /Users/moientajik/LMS/LMS.Service/src/LMS.API/bin/Debug/net8.0/LMS.Infrastructure.dll --project /Users/moientajik/LMS/LMS.Service/src/LMS.Infrastructure/LMS.Infrastructure.csproj --startup-assembly /Users/moientajik/LMS/LMS.Service/src/LMS.API/bin/Debug/net8.0/LMS.API.dll --startup-project /Users/moientajik/LMS/LMS.Service/src/LMS.API/LMS.API.csproj --project-dir /Users/moientajik/LMS/LMS.Service/src/LMS.Infrastructure/ --root-namespace LMS.Infrastructure --language C# --framework net8.0 --nullable --working-dir /Users/moientajik/LMS/LMS.Service --verbose
Using assembly 'LMS.Infrastructure'.
Using startup assembly 'LMS.API'.
Using application base '/Users/moientajik/LMS/LMS.Service/src/LMS.API/bin/Debug/net8.0'.
Using working directory '/Users/moientajik/LMS/LMS.Service/src/LMS.API'.
Using root namespace 'LMS.Infrastructure'.
Using project directory '/Users/moientajik/LMS/LMS.Service/src/LMS.Infrastructure/'.
Remaining arguments: .
Finding DbContext classes...
Finding IDesignTimeDbContextFactory implementations...
Finding application service provider in assembly 'LMS.API'...
Finding Microsoft.Extensions.Hosting service provider...
Using environment 'Local'.
Using application service provider from Microsoft.Extensions.Hosting.
Found DbContext 'LmsDBContext'.
Finding DbContext classes in the project...
Using context 'LmsDBContext'.
Microsoft.EntityFrameworkCore.Design.OperationException: Unable to create a 'DbContext' of type 'LmsDbContext'. The exception 'Entity type 'Journey' references entities mapped to JSON but is not itself mapped to a table or a view. This is not supported.' was thrown while attempting to create an instance. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
 ---> System.InvalidOperationException: Entity type 'Journey' references entities mapped to JSON but is not itself mapped to a table or a view. This is not supported.
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.ValidateJsonEntitiesNotMappedToTableOrView(IEnumerable`1 entityTypes)
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.ValidateJsonEntities(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.SqlServer.Infrastructure.Internal.SqlServerModelValidator.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.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(ServiceIdentifier serviceIdentifier, 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_InternalServiceProvider()
   at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance()
   at Microsoft.EntityFrameworkCore.Infrastructure.Internal.InfrastructureExtensions.GetService(IInfrastructure`1 accessor, Type serviceType)
   at Microsoft.EntityFrameworkCore.Infrastructure.Internal.InfrastructureExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
   --- End of inner exception stack trace ---
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Unable to create a 'DbContext' of type 'LmsDbContext'. The exception 'Entity type 'Journey' references entities mapped to JSON but is not itself mapped to a table or a view. This is not supported.' was thrown while attempting to create an instance. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728

When moving the entity configuration from the base class to concrete ones, I get a different error:

internal sealed class ModuleConfiguration : IEntityTypeConfiguration<Module>
{
  public void Configure(EntityTypeBuilder<Module> builder)
  {
    builder.ToTable("Modules");

    builder.OwnsMany(journey => journey.ContentOrders, navBuilder => navBuilder.ToJson());
  }
}

internal sealed class CourseConfiguration : IEntityTypeConfiguration<Course>
{
  public void Configure(EntityTypeBuilder<Course> builder)
  {
    builder.ToTable("Courses");

    builder.OwnsMany(journey => journey.ContentOrders, navBuilder => navBuilder.ToJson());
  }
}

internal sealed class CertificateProgramConfiguration : IEntityTypeConfiguration<CertificateProgram>
{
  public void Configure(EntityTypeBuilder<CertificateProgram> builder)
  {
    builder.ToTable("CertificatePrograms");

    builder.OwnsMany(journey => journey.ContentOrders, navBuilder => navBuilder.ToJson());
  }
}

Error:

[09:41:35 WRN]:[Microsoft.EntityFrameworkCore.Model] The navigation 'Journey.ContentOrders' was first mapped explicitly and then ignored. Consider not mapping the navigation in the first place.
Unable to create a 'DbContext' of type 'LmsDbContext'. The exception 'Entity type 'Journey' references entities mapped to JSON. Only TPH inheritance is supported for those entities.' was thrown while attempting to create an instance. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728

The question is, why only TPH is supported for this case?

Include provider and version information

EF Core version: 8.0.0-rc.1.23419.6 Database provider: Microsoft.EntityFrameworkCore.SqlServer Target framework: .NET 8 Operating system: Mac M1 Sonoma

ajcvickers commented 10 months ago

Duplicate of #28443