How to configure a foreign key on an owned EF entity's property?

ef-code-first entity-framework-core

Question

EF Core 3.0

I have the following (simplified) entities in my domain:

class ApplicationUser {
    public int Id { get; set; }
    public string UserName { get; set; }
    // other properties
}

[Owned]
class Stamp {
    public string Username { get; set; }
    public ApplicationUser User { get; set; }
    DateTime DateTime { get; set; }
}

class Activity {
    public Stamp Created { get; set; }
    public Stamp Modified { get; set; }
    // other properties
}

It's not particularly relevant, but it's worth mentioning that ApplicationUser.UserName is a non-primary, unique key. (ApplicationUser actually inherits from ASP.NET IdentityUser.)

I want to enforce that Stamp.Username is a foreign key referencing ApplicationUser.UserName.

If Stamp was a regular, non-owned entity, this would have set up that relationship:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    // Stamp.Username => ApplicationUser.UserName
    modelBuilder.Entity<Stamp>(e => {
        e.HasOne(s => s.User)
        .WithOne()
        .HasForeignKey<Stamp>(s => s.Username)
        .HasPrincipalKey<ApplicationUser>(u => u.UserName);
    });
    ...
}

When I try to create a migration (dotnet ef migrations add) I get an InvalidOperationException saying "The type 'Stamp' cannot be configured as non-owned because an owned entity type with the same name already exists".

How to achieve what I'm trying to do, using Fluent API or otherwise?

1
0
10/2/2019 3:49:11 PM

Popular Answer

This is one possible solution, likely not the most ellegant one. It is based on this answer mentioned by ChW in the comments.

modelBuilder.Entity<Activity>(e => {
    e.OwnsOne(a => a.Created)
    .HasOne<ApplicationUser>()
    .WithOne()
    .HasForeignKey<Stamp>(s => s.Username)
    .HasPrincipalKey<ApplicationUser>(u => u.UserName);
});

This sets up the required foreign key on a particular Stamp occurence (Created) for a particular owner entity (Activity).

A similar block of code would obviously need to be repeated for every other Stamp occurence (in this example, Modified) and for every other owner entity (Activity may not be the only one).

Btw, I also ended up removing the Stamp.User navigation property because EF has been using it to automatically create another foreign key that was (unwantedly) pointing to the ApplicationUser.Id property.

0
10/2/2019 7:47:20 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow