Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EF Core HasOptional WithOptionalDependent

I have the following tables in my database:

Product                                 ResourceAssociation
-------                                 ------------------
Name                          /-------> Id
ResourceAssociation_Id ------/         SomeProperty

So Product has a ResourceAssociation_Id, which is a FK to the ResourceAssociation table.

This is a legacy application that had an Entity Framework 6 map that contained this piece of code:

HasOptional(t => t.ResourceAssociation).WithOptionalDependent().WillCascadeOnDelete(true);

I'm looking to port this to EF Core. EF Core doesn't have the HasOptional anymore, it seems. I've tried this:

builder.HasOne(t => t.ResourceAssociation)
    .WithOne().HasForeignKey("ResourceAssociation_Id")
    .IsRequired(false)
    .OnDelete(DeleteBehavior.Cascade);

I've also tried replacing the WithOne with WithMany. But it doesn't work.

When I try to create a new Product, without a ResourceAssociation (because it isn't required), EF Core still tells me my ModelState is invalid because the ResourceAssociation is null.

I can't specify the property in WithOne (e.g. WithOne(x => x.Product)) because ResourceAssociation is a table that will also be used for other tables (for example Brand also has a ResourceAssociation_Id column pointing to that table).

Is this kind of setup even possible in EF Core? Or will I have to add the different navigation properties to my ResourceAssociation class (ie Product, Brand,...)?

like image 295
Peter Avatar asked Nov 24 '25 22:11

Peter


1 Answers

In EF Core, HasOne / WithOne (even with navigation properties) are not enough for determining which is the principal and which is the dependent entity in the one-to-one relationship (for one-to-many the one is always principal, many is the dependent, and for many-to-many there is not principal/dependent).

Because of that, the generic type argument of HasForeignKey / HasPrincipalKey is required for determination of respectively dependent / principal entity. This is actually explained in the Other Relationship Patterns - One-to-one EF Core documentation topic:

When configuring the relationship with the Fluent API, you use the HasOne and WithOne methods.

When configuring the foreign key you need to specify the dependent entity type - notice the generic parameter provided to HasForeignKey in the listing below. In a one-to-many relationship it is clear that the entity with the reference navigation is the dependent and the one with the collection is the principal. But this is not so in a one-to-one relationship - hence the need to explicitly define it.

So what you need here is to specify Product as being the dependent of the relationship, along with the FK property / column name:

builder.HasOne(t => t.ResourceAssociation)
    .WithOne() // ok, no navigation
    .HasForeignKey<Product>("ResourceAssociation_Id") // FK name in the dependent
    //               ^^^ the dependent entity of the relationship
    .IsRequired(false)
    .OnDelete(DeleteBehavior.Cascade);
like image 155
Ivan Stoev Avatar answered Nov 26 '25 11:11

Ivan Stoev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!