[英]hibernate (or SQL or HQL) finding objects who have a collection which is a subset of another collection
故事:
我有这个用户->角色->特权机制。 每个用户都有一些角色。 每个角色都有一些特权。
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。我想知道该用户可以进入哪些房间。 如何使用休眠条件或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来实现此目标,请随时回复。 干杯!!!
第一个查询获取用户有权访问的所有房间。第二个查询获取不需要任何特权的所有房间。 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 )
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(不包含不同的/分组子句)。
数据库通常将IN子选择转换为半联接,而不是IN转换为半反联接,这意味着:未分配联接表中的值,并且多个联接匹配项的结果将不相乘。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.