EF4.2 additional left outer joint with one table
I know there are some questions about this already, most refer to either old issues that have been resolved or a few tables. This issue is not addressed in any of the other problems "left outer join" that I have seen, I receive INNER JOIN
and LEFT OUTER JOIN
for the same table with the same request.
Table outline:
Users: id (PK)
Name (VARCHAR)
ProfileImageUri (VARCHAR)
Locations: id (PK)
LocationBPNTips: id (PK)
TipText (VARCHAR)
CreatedAt (Datetime)
UserId (int) (FK to User.id, navigation property is called User)
LocationId (int) (FK to Location.id)
(there is more, but this is not relevant :))
In my scenario, I am querying a referenced table through a projection and I get an extra left outer join, this is what I am running (the commented parts are not relevant to the problem, commented out for cleaner SQL, EF does (even better than I imagine represented :)):
LocationBPNTips
.Where(t => t.LocationId == 33)
//.OrderByDescending(t => intList.Contains(t.UserId))
//.ThenByDescending(t => t.CreatedAt)
.Select(tip => new LocationTipOutput
{
CreatedAt = tip.CreatedAt,
Text = tip.TipText,
LocationId = tip.LocationId,
OwnerName = tip.User.Name,
OwnerPhoto = tip.User.ProfileImageUri
}).ToList();
And this is the generated SQL
SELECT
[Extent1].[LocationId] AS [LocationId],
[Extent1].[CreatedAt] AS [CreatedAt],
[Extent1].[TipText] AS [TipText],
[Extent2].[Name] AS [Name],
[Extent3].[ProfileImageUri] AS [ProfileImageUri]
FROM [dbo].[LocationBPNTips] AS [Extent1]
INNER JOIN [dbo].[Users] AS [Extent2] ON [Extent1].[UserId] = [Extent2].[Id]
LEFT OUTER JOIN [dbo].[Users] AS [Extent3] ON [Extent1].[UserId] = [Extent3].[Id]
WHERE 33 = [Extent1].[LocationId]
As you can see is LEFT OUTER JOIN
executed on the same tableINNER JOIN
I think the optimal code would be (note: I renamed Extent3 to Extent2 manually and added a comment, this was not generated by EF !!) - with my current data it runs about 22% faster (with sorting, this% should be higher no sorting) since no additional connection is needed.
SELECT
[Extent1].[LocationId] AS [LocationId],
[Extent1].[CreatedAt] AS [CreatedAt],
[Extent1].[TipText] AS [TipText],
[Extent2].[Name] AS [Name],
[Extent2].[ProfileImageUri] AS [ProfileImageUri]
FROM [dbo].[LocationBPNTips] AS [Extent1]
INNER JOIN [dbo].[Users] AS [Extent2] ON [Extent1].[UserId] = [Extent2].[Id]
--LEFT OUTER JOIN [dbo].[Users] AS [Extent3] ON [Extent1].[UserId] = [Extent3].[Id]
WHERE 33 = [Extent1].[LocationId]
Various queries I have tried (projection of anonymous type in them):
LocationBPNTips
.Where(t => t.LocationId == 33)
//.OrderByDescending(t => intList.Contains(t.UserId))
//.ThenByDescending(t => t.CreatedAt)
.Select(tip => new
{
CreatedAt = tip.CreatedAt,
Text = tip.TipText,
LocationId = tip.LocationId,
OwnerName = tip.User,
OwnerPhoto = tip.User
}).ToList()
The SQL output was flawed, it double-sampled the users table in the same format as above, internal and then external. I think I understand why this is happening in this case, because I was querying for the data twice, although this could have been done in memory and not SQL with an extra join - but in my case I did not ask twice, I asked for different columns just one time. I did this test to make sure the double join is consistent.
I also tried to run:
LocationBPNTips
.Where(t => t.LocationId == 33)
.Select(tip => new
{
CreatedAt = tip.CreatedAt,
Text = tip.TipText,
LocationId = tip.LocationId,
OwnerName = tip.User.Name
}).ToList()
This returns a clean, single inner join as expected, but that's not what I am trying to do
So the question is : Is this a bug? Am I using EF wrong?
source to share
I've seen a similar issue before. We can call this a bug or a feature. EF Query Building is far from ideal. The ADO.NET team fixes some issues with each major release. I don't have the June 2011 CTP installed to check if this also happens when I first view the next version.
Edit:
As per this answer, a similar issue was fixed in the June CTP 2011.
source to share