WithOptionalDependent vs WithOptionalPrinciple - Definitive Answer?

C#Entity FrameworkEf Code-First

C# Problem Overview


I thought it might be helpful to get a definitive answer on when to use WithOptionalDependent and when to use WithOptionalPrincipal. The help for the two functions is a little unclear, and I find myself digging through multiple Stack Overflow answers and answers on other sites combining answers in order to feel confident I've got the relationship going the correct direction.

Here's what MSDN says about WithOptionalDependent:

> Configures the relationship to be optional:optional without a > navigation property on the other side of the relationship. The entity > type being configured will be the dependent and contain a foreign key > to the principal. The entity type that the relationship targets will > be the principal in the relationship.

and here is what it says about WithOptionalPrincipal:

> Configures the relationship to be optional:optional without a > navigation property on the other side of the relationship. The entity > type being configured will be the principal in the relationship. The > entity type that the relationship targets will be the dependent and > contain a foreign key to the principal.

The line "The entity type being configured" is the part that always confuses me (and I assume others).

In this example:

class MyEntityA
{
    [Key]
    public int Id { get; set; }
    public int BId { get; set; }
    [ForeignKey("BId")]
    public MyEntityB B { get; set; }
}

class MyEntityB
{
    [Key]
    public int Id { get; set; }
}

modelBuilder.Entity<MyEntityA>().HasOptional(a => a.B).WithOptionalDependent();

is "The entity type being configured" referring to MyEntityA or MyEntityB? I assume it is the former.

If that's correct, what's an example of when you'd use WithOptionalPrincipal?

I actually think in my code example it should really be WithMany and neither of the WithOptional options. Clearly I'm still confused!

There are overloads for both of these functions that take the navigation property going the other direction. I assume those overloads don't change those answers, but please correct me if I'm wrong.

I hope this will be helpful to the larger community as well.

C# Solutions


Solution 1 - C#

For example, lets modify your EntityB by navigation property and make BId nullable (as we are talking about optional relationship).

class MyEntityA
{
    [Key]
    public int Id { get; set; }
    public int? BId { get; set; }

    [ForeignKey("BId")]
    public virtual MyEntityB B { get; set; }
}

class MyEntityB
{
    [Key]
    public int Id { get; set; }

    public virtual MyEntityA A { get; set; }
}

then we can use:

modelBuilder.Entity<MyEntityB>().HasOptional(a => a.A).WithOptionalPrincipal();

MyEntityA has FK to MyEntityB, so in your example you configure MyEntityA and use WithOptionalDependent. But you can start configuration from MyEntityB-side, then you need WithOptionalPrincipal.

Solution 2 - C#

The answer to your question is: "The entity type being configured" is MyEntityA

This can be seen definitively by looking at the documentation for

OptionalNavigationPropertyConfiguration<TEntityType, TTargetEntityType>

which is the type returned by HasOptional and which says:

> TTargetEntityType

> The entity type that the relationship targets.

which provides more context for the phrases: > The entity type being configured

> The entity type that the relationship targets

So, in your case you get back from HasOptional an

OptionalNavigationPropertyConfiguration<MyEntityA, MyEntityB>

Thus, WithOptionalDependent means that MyEntityB will be the Principal with an optional Navigation Property pointing back to MyEntityA (specified via the overload's lambda parameter) and MyEntityA will be the Dependent and contain a Foreign Key and Navigation Property (as specified in the lambda parameter of HasOptional). This is the scenario in your model.

Conversely, WithOptionalPrincipal means that MyEntityA will be the Principal and MyEntityB the Dependent with Foreign Key and Navigation Property.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTimView Question on Stackoverflow
Solution 1 - C#JurekView Answer on Stackoverflow
Solution 2 - C#ErikestView Answer on Stackoverflow