With the following one-to-one models, both with navigation properties:-
public class Foo
{
public int Id { get; set; }
public virtual Bar Bar { get; set; }
}
public class Bar
{
public int Id { get; set; }
public virtual Foo Foo { get; set; }
}
Foo has an optional Bar.
Bar has a required Foo.
I have the following mapping on Bar:-
HasRequired(x => x.Foo)
.WithOptional(x => x.Bar)
.Map(x => x.MapKey("FooId"));
Which creates the foreign key on the Bar table named 'FooId'.
All this works fine, except it generates the sql for Foo with a 'Left Outer Join' to Bar on all queries when its not needed.
SELECT ..
[Extent2].[Id] AS [Id1]
FROM [dbo].[Foo] AS [Extent1]
LEFT OUTER JOIN [dbo].[Bar] AS [Extent2] ON [Extent1].[Id] = [Extent2].[FooId]
Looking closer it only returns the Bar's Id.
Searching stack I can see most suggestions to use .WithMany
instead of .WithOptional
, but I need the navigation properties.
Any suggestions?
A left outer join is a join in which each element of the first collection is returned, regardless of whether it has any correlated elements in the second collection. You can use LINQ to perform a left outer join by calling the DefaultIfEmpty method on the results of a group join.
There really is no difference between a LEFT JOIN and a LEFT OUTER JOIN. Both versions of the syntax will produce the exact same result in PL/SQL. Some people do recommend including outer in a LEFT JOIN clause so it's clear that you're creating an outer join, but that's entirely optional.
A left outer join is a method of combining tables. The result includes unmatched rows from only the table that is specified before the LEFT OUTER JOIN clause. If you are joining two tables and want the result set to include unmatched rows from only one table, use a LEFT OUTER JOIN clause or a RIGHT OUTER JOIN clause.
A Left Outer Join will return all the rows from table 1 and only those rows from table 2 which are common to table 1 as well. A Right Outer Join will do just the opposite.
This is the standard behavior for one-to-one FK association and cannot be avoided. What EF does is to maintain internally a hidden (shadow) property like int? BarId
for the Foo
entity.
The only way to get rid of LEFT OUTER JOIN
s and keep bidirectional navigation properties is if you can afford changing the Bar
db model (table) to use the (default EF one-to-one model) Shared Primary Key Association by basically removing the Map
call from the fluent configuration:
HasRequired(x => x.Foo)
.WithOptional(x => x.Bar);
In this model the Bar
table will not contain FooId
FK column, but instead the PK column Id
will no more be identity and will also serve as FK referencing Foo
table.
This allows EF to not care maintaining a BarId
in Foo
since it knows that if there is corresponding Bar
, it would be with Id
same as Foo.Id
.
If you can't change the database design, then you are out of luck - you have to either live with LEFT OUTER JOIN
s, or sacrifice the Foo.Bar
navigation property and configure the relationship as unidirectional one-to-many as you already mentioned.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With