2

I have an entity named User and a value object named UserRef containing UserId.

EF is picking up the UserId on the UserRef and trying to map it to a User.

This isn't intended as this entity is for DDD, and I have no interest in using it as a navigational property.

If I rename the UserRef property to User_Id, everything works fine.

How can I tell EF to leave the property alone, and stop trying to do anything with it (other than read/write its value)?

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

    public UserRef? ArchivedByUser { get; private set; }
}

public class UserRef
{
    public Guid UserId { get; private set; }
}

public class UserConfiguration : IEntityTypeConfiguration<User>
{
    public void Configure(EntityTypeBuilder<User> builder)
    {
        builder.HasKey(o => o.Id);

        builder.OwnsOne(o => o.ArchivedByUser, archivedByUser => {
            archivedByUser.Property(userRef => userRef.UserId)
                            .HasColumnName("ArchivedByUser");
        });

    }
}

I get the following error:

The keys {'UserId'} on 'User.ArchivedByUser#UserRef' and {'Id'} on 'User' are both mapped to 'User.PK_User' but with different columns ({'ArchivedByUser'} and {'Id'}).

Thanks!

Beakie
  • 1,948
  • 3
  • 20
  • 46
  • All types that map to the same table, must have the same primary key. So that EF Core can map them to the same row. This includes owned types. Usually an owned type will have shadow properties for the PK, but you are triggering a naming convention. – Jeremy Lakeman Jan 28 '22 at 02:31
  • The default shadow property name for foreign keys is "". So your explicit `UserId` property is being used as the PK / FK, instead of generating a shadow property. Since there's no mention of any naming restrictions (https://learn.microsoft.com/en-us/ef/core/modeling/owned-entities#implicit-keys) perhaps you should raise an issue to either document the behaviour better, or generate unlikely / impossible property names https://github.com/dotnet/efcore/issues ? – Jeremy Lakeman Jan 28 '22 at 04:31

1 Answers1

1

Owned entities have implicit key (shared PK/FK of one-to-one relationship with owner) which by convention is shadow property named <owner entity name><owner entity key name>.

Which in this particular case is UserId and matches the class property with the same name and type, so EF decides that it should be used for the aforementioned purpose.

As usual when EF conventions do not work, you resort to explicit configuration. In this case it is enough to specify different shadow property name to be used as PK/FK. e.g.

archivedByUser.WithOwner().HasForeignKey("OwnerId");

The name is arbitrary since there is no table column associated with it.

The above fluent API call is enough to achieve the goal. But if you want to be absolutely sure/maximum explicit, then the full configuration is like

const string KeyPropertyName = "OwnerId";
archivedByUser.Property<Guid>(KeyPropertyName);
archivedByUser.HasKey(KeyPropertyName);
archivedByUser.WithOwner().HasForeignKey(KeyPropertyName);
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343