{"action":"opened","issue":{"url":"https://api.github.com/repos/aspnet/EntityFramework/issues/7240","repository_url":"https://api.github.com/repos/aspnet/EntityFramework","labels_url":"https://api.github.com/repos/aspnet/EntityFramework/issues/7240/labels{/name}","comments_url":"https://api.github.com/repos/aspnet/EntityFramework/issues/7240/comments","events_url":"https://api.github.com/repos/aspnet/EntityFramework/issues/7240/events","html_url":"https://github.com/aspnet/EntityFramework/issues/7240","id":195263672,"number":7240,"title":"Relational model builder: Consistently map shadow FK properties","user":{"login":"HappyNomad","id":3721251,"avatar_url":"https://avatars.githubusercontent.com/u/3721251?v=3","gravatar_id":"","url":"https://api.github.com/users/HappyNomad","html_url":"https://github.com/HappyNomad","followers_url":"https://api.github.com/users/HappyNomad/followers","following_url":"https://api.github.com/users/HappyNomad/following{/other_user}","gists_url":"https://api.github.com/users/HappyNomad/gists{/gist_id}","starred_url":"https://api.github.com/users/HappyNomad/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/HappyNomad/subscriptions","organizations_url":"https://api.github.com/users/HappyNomad/orgs","repos_url":"https://api.github.com/users/HappyNomad/repos","events_url":"https://api.github.com/users/HappyNomad/events{/privacy}","received_events_url":"https://api.github.com/users/HappyNomad/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2016-12-13T14:15:02Z","updated_at":"2016-12-13T14:15:02Z","closed_at":null,"body":"The [documentation](https://docs.microsoft.com/en-us/ef/core/modeling/relationships#no-foreign-key-property) says that I'm not required to have FK properties in my model, and instead I can rely on the model builder to generate them as shadow properties.  This works in most cases, but I've discovered an inconsistency, demonstrated by the below _Scenario 4_, regarding how those shadow properties are mapped to the database.\r\n\r\nI kept the below pseudocode concise for readability, so first note the following:\r\n- `Parent` and `Child` entities each have an `Id` property.\r\n- Every property has an auto-implemented getter and setter.\r\n- Entities and their properties are public.\r\n- No navigations exist from dependant back to principle.\r\n- Mappings are by convention except where the fluent API is mentioned.\r\n- _Disjoint child subclasses_ 1 and 2 directly derive from a common base class that's also mapped.\r\n\r\n**Scenario 1**\r\n\r\n\tclass Parent { IList<Child> A; IList<Child> B; }\r\n\r\nGenerates `ParentId` and `ParentId1` shadow FK properties on `Child`.  These then map to respective FKs in the database.\r\n\r\n**Scenario 2**\r\n\r\n\tclass Parent { IList<DisjointChildSubclass1> A; IList<DisjointChildSubclass2> B; }\r\n\r\nGenerates a `ParentId` shadow FK property for each subclass.  These then map to a single FK in the database.\r\n\r\n**Scenario 3**\r\n\r\n\tclass Parent { Child A; IList<Child> B; }\r\n\r\nRequires fluent API to specify correct dependant.  Specifying a `ParentId` shadow FK property on `Child` to correspond to `A` causes the shadow property corresponding to `B` to generate as `ParentId1`.  These then map to respective FKs in the database.\r\n\r\n**Scenario 4**\r\n\r\n\tclass Parent { DisjointChildSubclass1 A; IList<DisjointChildSubclass2> B; }\r\n\r\nRequires fluent API to specify correct dependant.  Specifying a `ParentId` shadow FK property on `Child` to correspond to `A` throws an exception (see below).  This is inconsistent.  It should work similarly to _Scenario 3_.\r\n\r\n\tpublic class BloggingContext : DbContext\r\n\t{\r\n\t\tpublic BloggingContext( DbContextOptions<BloggingContext> options )\r\n\t\t\t: base( options ) { }\r\n\r\n\t\tpublic DbSet<Parent> Parents { get; set; }\r\n\t\tpublic DbSet<Child> Children { get; set; }\r\n\r\n\t\tprotected override void OnModelCreating( ModelBuilder modelBuilder )\r\n\t\t{\r\n\t\t\tmodelBuilder.Entity<Parent>()\r\n\t\t\t\t.HasOne( p => p.A )\r\n\t\t\t\t.WithOne()\r\n\t\t\t\t.HasForeignKey<DisjointChildSubclass1>( \"ParentId\" );\r\n\t\t}\r\n\t}\r\n\r\n\tpublic class Parent\r\n\t{\r\n\t\tpublic int Id { get; set; }\r\n\t\tpublic DisjointChildSubclass1 A { get; set; }\r\n\t\tpublic IList<DisjointChildSubclass2> B { get; set; }\r\n\t}\r\n\r\n\tpublic abstract class Child\r\n\t{\r\n\t\tpublic int Id { get; set; }\r\n\t}\r\n\r\n\tpublic class DisjointChildSubclass1 : Child { }\r\n\r\n\tpublic class DisjointChildSubclass2 : Child { }\r\n\r\nI just restored the sample project from the `dev` feed to `1.2.0-preview1-22878` and retested all scenarios.  The exception for _Scenario 4_ says:\r\n\r\n>`System.InvalidOperationException` was unhandled by user code\r\n>  **HResult=**-2146233079\r\n>  **Message=** The foreign keys {`ParentId`} on `DisjointChildSubclass2` and {`ParentId`} on `DisjointChildSubclass1` are both mapped to `Children.FK_Children_Parents_ParentId` but with different uniqueness.\r\n>  **Source=**`Microsoft.EntityFrameworkCore`\r\n>  **StackTrace:**\r\n>       at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ShowError(String message)\r\n>       at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.EnsureSharedForeignKeysCompatibility(IModel model)\r\n>       at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model)\r\n>       at Microsoft.EntityFrameworkCore.Infrastructure.SqlServerModelValidator.Validate(IModel model)\r\n>       at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator)\r\n>       at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.<>c__DisplayClass19_0.<GetModel>b__0(Object k)\r\n>       at System.Collections.Concurrent.ConcurrentDictionary'2.GetOrAdd(TKey key, Func'2 valueFactory)\r\n>       at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator)\r\n>       at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()\r\n>       at Microsoft.EntityFrameworkCore.Internal.LazyRef'1.get_Value()\r\n>       at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()\r\n>       at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServiceCollectionExtensions.<>c.<AddEntityFramework>b__0_6(IServiceProvider p)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactoryService(FactoryService factoryService, ServiceProvider provider)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor'2.VisitCallSite(IServiceCallSite callSite, TArgument argument)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProvider provider)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor'2.VisitCallSite(IServiceCallSite callSite, TArgument argument)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProvider provider)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor'2.VisitCallSite(IServiceCallSite callSite, TArgument argument)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProvider provider)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor'2.VisitCallSite(IServiceCallSite callSite, TArgument argument)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(IServiceCallSite callSite, ServiceProvider provider)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass16_0.<RealizeService>b__0(ServiceProvider provider)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)\r\n>       at Microsoft.EntityFrameworkCore.Storage.DatabaseProviderServices.GetService[TService]()\r\n>       at Microsoft.EntityFrameworkCore.Storage.Internal.SqlServerDatabaseProviderServices.get_RelationalDatabaseCreator()\r\n>       at Microsoft.EntityFrameworkCore.Storage.RelationalDatabaseProviderServices.get_Creator()\r\n>       at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServiceCollectionExtensions.<>c.<AddEntityFramework>b__0_13(IServiceProvider p)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactoryService(FactoryService factoryService, ServiceProvider provider)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor'2.VisitCallSite(IServiceCallSite callSite, TArgument argument)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProvider provider)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor'2.VisitCallSite(IServiceCallSite callSite, TArgument argument)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(IServiceCallSite callSite, ServiceProvider provider)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass16_0.<RealizeService>b__0(ServiceProvider provider)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)\r\n>       at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)\r\n>       at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure'1 accessor)\r\n>       at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.get_DatabaseCreator()\r\n>       at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.EnsureDeleted()\r\n>       at EFGetStarted.AspNetCore.NewDb.Startup.Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, BloggingContext dataContext) in C:\\Users\\Adrian\\Development\\Examples\\ASP.NET Core\\EFGetStarted.AspNetCore.NewDb\\src\\EFGetStarted.AspNetCore.NewDb\\Startup.cs:line 58\r\n>  **InnerException**: \r\n"}}
{"actor":{"display_login":"HappyNomad"}}