我有这个数据库架构:
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那样高效。有没有其他人在我面前遇到这个并想出一个解决方案?
答案 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() == 0
(query
)创建以下SQL,该SQL仅加入x == 1
和User
表:
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 )
不再有章节表,解决了你的问题。
(虽然将逻辑添加到您的应用程序中需要额外的编码)