Reputation: 55
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?
Upvotes: 0
Views: 6385
Reputation: 1681
One possible lead to explore : WithOwner() .HasForeignKey(...)
(Found in the help page https://learn.microsoft.com/en-us/ef/core/modeling/owned-entities )
//Please note that I wasn't 100% of the syntax when using
// 'OwnsOne<Stamp>(builder => ...)'
// instead of
// 'OwnsOne(user => user.Stamp, builder => ...)'
modelBuilder.Entity<ApplicationUser>().OwnsOne<Stamp>(
subBuilder =>
{
subBuilder.WithOwner().HasForeignKey("ApplicationUserId");
});
Upvotes: 2
Reputation: 2958
You should configure it in the owner using OwnsOne:
modelBuilder.Entity<ApplicationUser>().OwnsOne(user => user.Stamp, stamp =>
{
// configure your stamp
});
Upvotes: 1
Reputation: 55
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.
Upvotes: 0