Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mapping exception with property called FooId on base type Foo in TPT #23092

Closed
marinasundstrom opened this issue Oct 24, 2020 · 2 comments
Closed
Labels
area-model-building closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported Servicing-approved type-bug
Milestone

Comments

@marinasundstrom
Copy link

File a bug

Fails to map property in Table-per-Type inheritance (SQL Server provider)

System.InvalidOperationException: "The property 'ObjectId' on entity type 'EntityType: Object Abstract' is not mapped to the table 'Car'."

I think it is about the conventions. The type being named Object and assuming ``ObjectId```is a primary key that should be in the derived types table.

When I remove ObjectId everything works just fine.

I explored potential workarounds but not even renaming the column in the database an adding Column handles the problem. It still complains about not being able to map the property ObjectId to Car.

        [Column("ObjId")] // Still fails
        public int? ObjectId { get; set; }

Code

    [Table("Object")]
    public abstract class Object
    {
        [Key]
        public int Id { get; set; }

        public int? ObjectId { get; set; }
    }

    [Table("Car")]
    public partial class Car : Models.Object
    {
        [StringLength(15)]
        public string Registry { get; set; }
    }

Stack traces

   at Microsoft.EntityFrameworkCore.RelationalPropertyExtensions.FindSharedObjectRootProperty(IProperty property, StoreObjectIdentifier& storeObject)
   at Microsoft.EntityFrameworkCore.RelationalPropertyExtensions.FindSharedStoreObjectRootProperty(IProperty property, StoreObjectIdentifier& storeObject)
   at Microsoft.EntityFrameworkCore.RelationalPropertyExtensions.IsColumnNullable(IProperty property, StoreObjectIdentifier& storeObject)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.SqlServerIndexConvention.<>c__DisplayClass12_0.<CreateIndexFilter>b__0(IProperty property)
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.ToList()
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.SqlServerIndexConvention.CreateIndexFilter(IIndex index)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.SqlServerIndexConvention.SetIndexFilter(IConventionIndexBuilder indexBuilder, Boolean columnNameChanged)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.SqlServerIndexConvention.ProcessIndexAdded(IConventionIndexBuilder indexBuilder, IConventionContext`1 context)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnIndexAdded(IConventionIndexBuilder indexBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnIndexAddedNode.Run(ConventionDispatcher dispatcher)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.DelayedConventionScope.Run(ConventionDispatcher dispatcher)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ConventionBatch.Run()
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ConventionBatch.Dispose()
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelFinalizing(IConventionModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelFinalizing(IConventionModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel()
   at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel()
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, ModelDependencies modelDependencies)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder, ModelDependencies modelDependencies)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
   at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__7_3(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 singletonCallSite, 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 singletonCallSite, 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__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.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_InternalServiceProvider()
   at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
   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.Collections.Generic.IAsyncEnumerable<TEntity>.GetAsyncEnumerator(CancellationToken cancellationToken)
   at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable`1.GetAsyncEnumerator()
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.<ToListAsync>d__65`1.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at ConsoleApp1.DataService.<Do>d__3.MoveNext() in X:\Nordengren\Yrsa\Support\ConsoleApp1\DataService.cs:line 38
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at ConsoleApp1.DataService.<StartAsync>d__2.MoveNext() in X:\Nordengren\Yrsa\Support\ConsoleApp1\DataService.cs:line 32
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at Microsoft.Extensions.Hosting.Internal.Host.<StartAsync>d__9.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.<RunAsync>d__4.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.<RunAsync>d__4.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at ConsoleApp1.Program.<Main>d__0.MoveNext() in X:\<Project>\ConsoleApp1\Program.cs:line 36

Provider and version information

EF Core version:
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: NET 5.0 RC2
Operating system:
IDE: Visual Studio 2019 16.3

@ajcvickers
Copy link
Contributor

ajcvickers commented Oct 27, 2020

@AndriySvyryd This feels like something we should patch. I haven't been able to come up with any workarounds; could you take a look?

Some repo code:

[Table("Foo")]
public abstract class Foo
{
    [Key]
    public int Id { get; set; }

    public int? FooId { get; set; }
}

[Table("Car")]
public partial class Car : Foo
{
    [StringLength(15)]
    public string Registry { get; set; }
}

public class Program
{
    public static void Main()
    {
        using var context = new BlogContext();

        context.Database.EnsureDeleted();
        context.Database.EnsureCreated();
    }
}

public class BlogContext : DbContext
{
    public DbSet<Foo> Foos { get; set; }
    public DbSet<Car> Cars { get; set; }

    static ILoggerFactory ContextLoggerFactory
        => LoggerFactory.Create(b => b.AddConsole().AddFilter("", LogLevel.Information));

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
            .UseSqlServer(Your.ConnectionString)
            .EnableSensitiveDataLogging()
            .UseLoggerFactory(ContextLoggerFactory);

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
    }
}

@AndriySvyryd
Copy link
Member

AndriySvyryd commented Oct 27, 2020

A workaround would be to configure the implicit relationship to the base type explicitly while the property is ignored:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Object>().Ignore(e => e.ObjectId);

    modelBuilder.Entity<Car>().HasOne<Object>().WithOne()
        .HasForeignKey<Car>(c => c.Id);

    modelBuilder.Entity<Object>().Property(e => e.ObjectId);
}

There are actually two bugs that together make this manifest:

  • An FK property is discovered for an identifying FK created by convention
  • SqlServerIndexConvention throws for inherited properties in TPT instead of silently ignoring them

AndriySvyryd added a commit that referenced this issue Oct 28, 2020
Silently ignore inherited properties in TPT in SqlServerIndexConvention

Fixes #23092
AndriySvyryd added a commit that referenced this issue Oct 28, 2020
AndriySvyryd added a commit that referenced this issue Oct 29, 2020
Silently ignore inherited properties in TPT in SqlServerIndexConvention

Fixes #23092
AndriySvyryd added a commit that referenced this issue Oct 29, 2020
@ajcvickers ajcvickers added this to the 5.0.x milestone Oct 30, 2020
@AndriySvyryd AndriySvyryd added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Nov 3, 2020
@AndriySvyryd AndriySvyryd modified the milestones: 5.0.x, 5.0.1 Nov 3, 2020
AndriySvyryd added a commit that referenced this issue Nov 12, 2020
@ajcvickers ajcvickers changed the title Fails to map property in Table-per-Type inheritance Mapping exception with property called FooId on base type Foo in TPT Dec 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-model-building closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported Servicing-approved type-bug
Projects
None yet
Development

No branches or pull requests

3 participants