【问题标题】:Force inner join with many-to-many relationship entity framework使用多对多关系实体框架强制内部连接
【发布时间】:2014-04-18 18:42:58
【问题描述】:

我的数据库中有一个多对多关系设置,如下所示:

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)

当我在 DbContext 上运行此 LINQ 查询时:

from u in Users 
from s in u.Skills 
where s.Id == 5 
select new 
{
    u.Id,
    s.Description
})

生成的 SQL 包含我想要的所有内部连接:

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]

但是,当我添加一个简单的额外 where 子句时:

from u in Users 
from s in u.Skills 
where s.Id == 5 
    && u.Last == "test"
select new 
{
    u.Id,
    s.Description
})

现在生成的 SQL 使用了子查询:

[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]

也许我遗漏了一些东西,但我认为 EF 只会将另一个联接添加回 User 表以进行此查询,并且能够在 User.Last 上执行 where 而不是执行子查询。有没有办法强制这种行为?难道我做错了什么?

谢谢。


更新

Cosmin,我希望查询结果如下:

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'

【问题讨论】:

  • 您是否希望您的查询类似于:SELECT * FROM (SELECT * from Users where ...) Usr inner join Skill where ...?
  • 内森,我看不出什么是重复的?据我所知,该连接看起来不像多对多。你能解释一下吗?
  • 我这里没有 VS:但在我看来,我们可以尝试这样的事情:dbcontext.users.where(x => x.id == 5).include("skills" )
  • @Nathan 不是重复的,因为在多对多中,实体模型中没有任何东西可以加入

标签: c# linq linq-to-entities entity-framework-5 linq-query-syntax


【解决方案1】:

看起来这是 EF 目前没有做的优化。就个人而言,除非性能成为问题,否则我会坚持使用它生成的子查询。

但如果您愿意放弃 User 和 Skill 的直接导航属性,您可以对中间表进行建模以获取您要查找的查询。

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; }
}

那么下面的查询将产生一个连接而不是子查询

 from x in db.UserSkills 
 where x.Skill.Id == 5 && x.User.Last == "test"
 select new {x.User.Id, x.Skill.Description};

【讨论】:

  • 谢谢乔希。我希望不必走那条路,但看起来要么就是这样,要么只是处理子查询。
【解决方案2】:

@ryanulit,您的问题是有效的,它是所有 Linq to Entities 的问题。请检查发布的 MS 论坛的 URL

MS Forum's URL

【讨论】:

  • -1 2008 年 9 月的一次讨论,即 Entity Framework 首次发布一个月后,与有关 EF 5 的问题无关。
  • @Stijn,EF 5 只有一些高级功能。这个 EF 5 仍然存在为每个 && 操作添加额外连接的问题。乔希给出的答案是避免这种情况的解决方法。
猜你喜欢
  • 2017-01-28
  • 2011-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多