故事:
我有这个用户 - >角色 - >特权机制。每个用户都有一些角色。每个角色都有一些特权。
CREATE TABLE user (id int);
INSERT INTO user VALUES (1);
INSERT INTO user VALUES (2);
INSERT INTO user VALUES (3);
CREATE TABLE role (id int);
INSERT INTO role VALUES (100);
INSERT INTO role VALUES (200);
CREATE TABLE user__role (user_id int, role_id int);
INSERT INTO user__role VALUES (1, 100);
INSERT INTO user__role VALUES (2, 200);
CREATE TABLE privilege (id int);
INSERT INTO privilege VALUES (1000);
INSERT INTO privilege VALUES (2000);
INSERT INTO privilege VALUES (3000);
INSERT INTO privilege VALUES (4000);
CREATE TABLE role__privilege (role_id int, privilege_id int);
INSERT INTO role__privilege VALUES (100, 1000);
INSERT INTO role__privilege VALUES (100, 3000);
INSERT INTO role__privilege VALUES (200, 2000);
(用户,角色和权限都有名称和其他东西。但我省略了它们以保持示例简单)
然后我有一些房间。你需要一些特权才能进入房间。
CREATE TABLE room (id int);
INSERT INTO room VALUES (11);
INSERT INTO room VALUES (22);
INSERT INTO room VALUES (33);
INSERT INTO room VALUES (44);
INSERT INTO room VALUES (55);
CREATE TABLE room__privilege (room_id int, privilege_id int);
INSERT INTO room__privilege VALUES (11, 1000);
INSERT INTO room__privilege VALUES (11, 3000);
INSERT INTO room__privilege VALUES (22, 2000);
INSERT INTO room__privilege VALUES (33, 3000);
INSERT INTO room__privilege VALUES (55, 1000);
INSERT INTO room__privilege VALUES (55, 2000);
INSERT INTO room__privilege VALUES (55, 3000);
这是交易:如果用户拥有房间所需的所有权限,则用户可以进入房间。如果房间不需要特权,那么任何人都可以进入。
就对象而言,我有类似
的东西class User {
int id;
Set<Role> roles;
}
class Role {
int id;
Set<Privilege> privileges;
}
class Room {
int id;
Set<Privilege> requirements;
}
现在我有一个用户说id = 1.我想知道这个用户可以输入哪些房间。如何使用hibernate条件或SQL实现此目的?
我想我可以使用一些查询来查找用户拥有的所有权限(并将它们存储在一个集合中)。然后我发现房间的要求是这个集合的一个子集。但我找不到合适的标准/限制。此外,在阅读了stackoverflow中的一些帖子后,我感觉整个事情可以通过单个SQL / HQL查询来完成。
请有人给我一些帮助。提前谢谢!
更新1
整个晚上我一直在努力。我设法得到了一些结果
SELECT requirements.room_id
FROM (
SELECT room.id AS room_id, room__privilege.privilege_id FROM room
JOIN room__privilege ON room__privilege.room_id = room.id
) requirements
INNER JOIN (
SELECT room__privilege.room_id, COUNT(*) as count FROM room__privilege
GROUP BY room__privilege.room_id
) hits ON requirements.room_id = hits.room_id
INNER JOIN (
SELECT user.id AS user_id, rp.privilege_id FROM user
JOIN user__role ur ON user.id = ur.user_id
JOIN role__privilege rp ON ur.role_id = rp.role_id
) up ON requirements.privilege_id = up.privilege_id
WHERE up.user_id = 1
GROUP BY requirements.room_id, up.user_id, hits.count HAVING COUNT(*) = hits.count
UNION
SELECT room.id FROM room
WHERE room.id NOT IN (
SELECT room_id FROM room__privilege
);
这似乎给了我想要的东西。我似乎相当复杂,我不确定我是否可以将其包含在标准或HQL中。
我检查了@Rajesh和@Erik Hart的答案。他们的查询似乎也适用于这个例子。我要做一个分析,看看哪个表现更好。
非常感谢你的帮助。对此,我真的非常感激。如果有人知道如何通过标准或HQL实现这一点,请不要犹豫回复。干杯!!!
答案 0 :(得分:1)
第一个查询是获取用户有权访问的所有房间 第二个查询提取所有不需要任何priveleges的房间。 UNION会给出理想的结果
select A.room_id
FROM(
SELECT room_id,
count(privilege_id) as count1
FROM room__privilege
GROUP BY room_id) A
INNER JOIN
(
SELECT room_id,
count(RP.privilege_id) as count2
FROM room__privilege RP
INNER join
(select RLP.privilege_id as privilege_id
FROM role__privilege RLP
inner join user__role UR
on UR.role_id = RLP.role_id
and UR.user_id = 1 ) T
on T.privilege_id = RP.privilege_id
group by room_id) B
ON A.count1 = B.count2
AND A.room_id = B.room_id
union
select R.id from Room R
where R.id not in ( select room_id from room__privilege )
答案 1 :(得分:1)
SQL将是:
select id from room where id not in (
select room_id from room_privilege where privilege_id not in (
select id from privilege where id in ( -- can omit
select privilege_id from role_privilege where role_id in (
select id from rol where id in ( -- can omit
select role_id from user_role where user_id in ( -- if user table omitted: user_id=@userid
select id from usr where id=1 -- can omit
)))))) -- remove closing brackets when omitting subselects!
在SQL Server中检查过这个(用户#1:11,33,44;#2:22,44;仅限#3:44),由于保留关键字,表名略有变化。
第2行选择用户没有的房间权限,这会阻止他进入。然后第1行选择房间而不阻止room_privileges。
主对象表上的选择通常可以省略(第一个除外),但也可以保留没有孤立交叉引用的安全性(如果没有被外键阻止,则删除级联)。
这应该返回不同的房间ID(没有distinct / group by子句)。
IN子选择通常由数据库转换为半连接,NOT IN转换为半反连接,这意味着:未分配连接表中的值,并且多个连接匹配的结果不会相乘。