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

Don't detect FK properties that match exactly the principal key properties #13274

Closed
Trapov opened this issue Sep 10, 2018 · 4 comments
Closed
Labels
breaking-change closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported type-enhancement
Milestone

Comments

@Trapov
Copy link

Trapov commented Sep 10, 2018

OwnsOne is throwing an exception when owned type has the same key name and type, even if the root entity id and the child entity id were marked with HasColumnName differently.

systems.Property(s => s.Id).HasColumnName("SystemId")
var accountForPartner = systems.OwnsOne(s => s.AccountForPartners);
accountForPartner
    .Property(ap => ap.Id)
    .HasColumnName("AccountForPartnerId")
    .IsRequired();
accountForPartner
    .Property(ap => ap.Number)
    .HasColumnName("AccountForPartnerNumber");

This code was working in the previous version(the latest working version is 2.0.3), but starting from 2.1.0 it doesn't work anymore.

Exception message:

The keys {'Id'} on 'System.AccountForPartners#Account' and {'Id'} on 'System' are both mapped to 'System.SystemId' but with different columns ({'AccountForPartnerId'} and {'SystemId'}).

Stack trace:

System.InvalidOperationException: The keys {'Id'} on 'System.AccountForPartners#Account' and {'Id'} on 'System' are both mapped to 'System.SystemId' but with different columns ({'AccountForPartnerId'} and {'SystemId'}).
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.ValidateSharedKeysCompatibility(IReadOnlyList`1 mappedTypes, String tableName)
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.ValidateSharedTableCompatibility(IModel model)
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator)
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
   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.Internal.InternalAccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func`1 factory)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)

Steps to reproduce

It throws when you try to add a migration dotnet ef migrations add [Name]

public class System
{
    public Guid Id { get; private set; }

    public Account AccountForPartners { get; private set; }

    private System() { }
}

public class Account
{
    public Guid Id { get; private set; }

    public string Number { get; private set; }

    private Account() { }
}

var systems = modelBuilder.Entity<System>().ToTable("System");
systems.HasKey(s => s.Id);
systems.Property(s => s.Id).HasColumnName("SystemId").IsRequired();

var accountForPartner = systems.OwnsOne(s => s.AccountForPartners);
accountForPartner.Property(ap => ap.Id).HasColumnName("AccountForPartnerId").IsRequired();
accountForPartner.Property(ap => ap.Number).HasColumnName("AccountForPartnerNumber");

Further technical details

EF Core version: 2.1.0-2.1.3
Database Provider: Npgsql.EntityFrameworkCore.PostgreSQL
Operating system: Windows 10
IDE: Visual Studio 2017 15.8.3

@ajcvickers
Copy link
Member

ajcvickers commented Sep 11, 2018

@Trapov The problem is that Account.Id is being picked up as the primary key, and hence is being used to relate the two entity types in the table. The way to override this is to tell EF to:

  • Create a shadow property to use instead of Id
  • Tell EF to use this relate the two entity types by using this as the FK
var accountForPartner = systems.OwnsOne(s => s.AccountForPartners);
accountForPartner.Property<Guid>("OwnedId");
accountForPartner.HasForeignKey("OwnedId");

@ajcvickers
Copy link
Member

Leaving this open for triage since this is a pretty obscure thing to have to do.

@ajcvickers
Copy link
Member

Triage discussion: we should look into not detecting PKs by convention on owned types, since it is uncommon that an owned type will have an explicitly declared PK. However, we can continue to look for an FK by convention.

@ZombieProtectionAgency
Copy link

I think I ran into this as well. I created an Owned class for a few common columns all of my tables share with a FK pointing to my Users table. Everything worked fine. until I tried to add that type to my User object. It just silently didn't add the column for the User FK. I had noticed that Owned columns were being prefixed with the property name and I didn't want that so I used the Column attribute to explicitly specify the name and started getting the error from the issue.

I tried to demo and summarize my issue on StackOverflow just incase I was doing something wrong. That is here, https://stackoverflow.com/questions/52958737/ef-core-2-1-saying-multiple-columns-have-been-added-to-the-primary-key-but-they

Finally, I removed the Owned class property from the "User" class and copy + pasted the columns onto the User class and it worked exactly as expected which makes me think this is a bug with OwnedAttribute and its handling, not my implementation.

public class Entity
{
    public Guid Id { get; set; }
    public OwnedEntity Owned { get; set; }

    [Column(nameof(ParentId))]
    public Guid ParentId { get; set; }
    [Column(nameof(Parent))]
    public Entity Parent { get; set; }
}

@AndriySvyryd AndriySvyryd changed the title OwnsOne is throwing an exception when owned type has the same key name and type Don't detect PK properties on reference owned types by convention Feb 6, 2019
@AndriySvyryd AndriySvyryd changed the title Don't detect PK properties on reference owned types by convention Don't detect FK properties on owned types that match exactly the principal key properties Feb 7, 2019
@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 Feb 7, 2019
@AndriySvyryd AndriySvyryd reopened this Feb 7, 2019
@ajcvickers ajcvickers modified the milestones: 3.0.0, 3.0.0-preview3 Feb 22, 2019
@AndriySvyryd AndriySvyryd changed the title Don't detect FK properties on owned types that match exactly the principal key properties Don't detect FK properties that match exactly the principal key properties Feb 27, 2019
@AndriySvyryd AndriySvyryd removed their assignment Feb 28, 2019
@ajcvickers ajcvickers modified the milestones: 3.0.0-preview3, 3.0.0 Nov 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking-change closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported type-enhancement
Projects
None yet
Development

No branches or pull requests

4 participants