在使用EF链接表时摆脱不必要的连接

时间:2011-12-30 15:49:08

标签: entity-framework orm linq-to-entities linktable

我有这个数据库架构:

User  <--  UserRole  -->  Role

Role表有几列,但我只对主键感兴趣,我可以从UserRole的外键获取它,所以我根本不需要加入Role表,但我不能弄清楚如何避免使用EF加入该表。

我试过这段代码:

context.Users.Where(u => u.UserId == x).Single().Roles.Select(r => r.RoleId);

这会生成两个查询。一个在用户表上,另一个在UserRole和Role的连接上。我当然可以通过使用.Include(“Roles”)或SelectMany()将其减少为一个查询,但该查询将连接三个表。有没有办法摆脱多余的联接?我希望我的SQL类似于:

SELECT u.*, ur.RoleId
FROM User u
LEFT OUTER JOIN UserRole ur on ur.UserId = u.UserId
WHERE ...

实际上我正在使用automapper,但我认为这个例子展示了同样的问题。角色是一个小桌子,所以这次我可以忍受性能损失,但它让我觉得我不能像手写SQL那样高效。有没有其他人在我面前遇到这个并想出一个解决方案?

2 个答案:

答案 0 :(得分:1)

您可以使用以下内容(我在此处不使用var来明确显示类型):

IQueryable<IEnumerable<int>> query = context.Users
    .Where(u => u.UserId == x)
    .Select(u => u.Roles.Select(r => r.RoleId));

IEnumerable<int> result = query.Single();

    如果UserId == x的用户不存在,则
  • 会引发异常。 (我想你想要这样,因为你在你的例子中使用Single。)
  • 返回用户RoleId的{​​{1}}个集合。如果用户没有任何角色,则该集合可以为空(x)。
  • result.Count() == 0query)创建以下SQL,该SQL仅加入x == 1User表:

    UserRoles

如果您不想区分用户是否存在或存在但没有角色,您可以使用此查询获得更简单的SQL:

SELECT 
[Project1].[UserId] AS [UserId], 
[Project1].[C1] AS [C1], 
[Project1].[RoleId] AS [RoleId]
FROM ( SELECT 
        [Extent1].[UserId] AS [UserId], 
        [Extent2].[RoleId] AS [RoleId], 
       CASE WHEN ([Extent2].[UserId] IS NULL) 
           THEN CAST(NULL AS int) 
           ELSE 1
       END AS [C1]
       FROM  [dbo].[Users] AS [Extent1]
       LEFT OUTER JOIN [dbo].[UserRoles] AS [Extent2]
           ON [Extent1].[UserId] = [Extent2].[UserId]
       WHERE 1 = [Extent1].[UserId]
     )  AS [Project1]
ORDER BY [Project1].[UserId] ASC, [Project1].[C1] ASC

如果用户没有角色,如果用户不存在,则返回空集合。但SQL非常简单:

IQueryable<int> query = context.Users
    .Where(u => u.UserId == x)
    .SelectMany(u => u.Roles.Select(r => r.RoleId));

IEnumerable<int> result = query.ToList();

因此,这里所涉及的表之间没有连接,查询只使用SELECT [Extent1].[RoleId] AS [RoleId] FROM [dbo].[UserRoles] AS [Extent1] WHERE 1 = [Extent1].[UserId] 链接表。

答案 1 :(得分:0)

我更有效地使用角色。

结帐Flags,以便为您的用户添加角色。

标志的作用:

使用以下命令创建一种枚举:

Administrator = 1
Moderator = 2
SuperUser = 4
User = 8
Visitor = 16

在Usertable as Integer中添加属性Role。

"User" = Administrator + Moderator --> Role =  3 ( 1 + 2 )
"User" = Moderator + SuperUser     --> Role =  6 ( 2 + 4 )
"User" = SuperUser + User          --> Role = 12 ( 4 + 8 )

不再有章节表,解决了你的问题。

(虽然将逻辑添加到您的应用程序中需要额外的编码)