问题
I have a many-to-many relationship setup in my database like so:
User
-------
Id (PK, Identity)
First
Last
...various other fields
Skill
-------
Id (PK, Identity)
Description
UserSkill
-----------
UserId (PK, FK on User.Id)
SkillId (PK, FK On Skill.Id)
When I run this LINQ query on the DbContext:
from u in Users
from s in u.Skills
where s.Id == 5
select new
{
u.Id,
s.Description
})
The SQL generated contains all inner joins which is what I want:
SELECT
[Extent1].[UserId] AS [UserId],
[Extent2].[Description] AS [Description]
FROM [dbo].[UserSkill] AS [Extent1]
INNER JOIN [dbo].[Skill] AS [Extent2] ON [Extent1].[SkillId] = [Extent2].[Id]
WHERE 5 = [Extent2].[Id]
However, when I add a simple extra where clause:
from u in Users
from s in u.Skills
where s.Id == 5
&& u.Last == "test"
select new
{
u.Id,
s.Description
})
The SQL generated now uses a sub-query:
[Extent1].[Id] AS [Id],
[Filter1].[Description] AS [Description]
FROM [dbo].[User] AS [Extent1]
INNER JOIN (SELECT [Extent2].[UserId] AS [UserId], [Extent3].[Description] AS [Description]
FROM [dbo].[UserSkill] AS [Extent2]
INNER JOIN [dbo].[Skill] AS [Extent3] ON [Extent3].[Id] = [Extent2].[SkillId]
WHERE 5 = [Extent3].[Id] ) AS [Filter1] ON [Extent1].[Id] = [Filter1].[UserId]
WHERE 'test' = [Extent1].[Last]
Maybe I am missing something, but I would think EF would just add another join back to the User table for this query and be able to do a where on User.Last instead of doing a sub-query. Is there any way to force this kind of behavior? Am I doing something wrong?
Thanks.
UPDATE
Cosmin, I am wanting the query to come out like this:
SELECT u.Id, s.Description
FROM [User] u INNER JOIN
[UserSkill] us ON u.Id = us.UserId INNER JOIN
[Skill] s ON us.SkillId = s.Id
WHERE s.Id = 2 AND u.Last = 'test'
回答1:
Looks like this is an optimization that EF does not currently do. Personally, I'd stick with the sub query it generates unless performance becomes a problem.
But if you are willing to lose the direct navigation properties for User and Skill, you can model the intermediate table to get the query you are looking for.
public class User
{
public int Id { get; set; }
public string First { get; set; }
public string Last { get; set; }
public virtual ICollection<UserSkill> UserSkills { get; set; }
}
public class UserSkill
{
public int Id { get; set; }
[Required]
public User User { get; set; }
[Required]
public Skill Skill { get; set; }
}
public class Skill
{
public int Id { get; set; }
public string Description { get; set; }
public virtual ICollection<UserSkill> UserSkills { get; set; }
}
Then the following query will produce a join instead of subquery
from x in db.UserSkills
where x.Skill.Id == 5 && x.User.Last == "test"
select new {x.User.Id, x.Skill.Description};
回答2:
@ryanulit, your issue is valid and it is an issue for all Linq to Entities. Please check the posted MS Forum's URL
MS Forum's URL
来源:https://stackoverflow.com/questions/23160224/force-inner-join-with-many-to-many-relationship-entity-framework