短縮版
ユーザーテーブルがロールテーブルにリンクされ、ロールテーブルが権限にリンクされている基本的なセットアップがあります。これらは両方とも多対多の関係です。ロールは動的なエンティティであり、アプリケーションにとって重要ではありません (視覚的な側面のみ)。ユーザーをフェッチするときに、すべての権利の名前のリストを含むユーザー テーブルのデータを返したいと考えています。
明確にするために、これが私がソリューションに求めていることです:
ユーザーオブジェクトで権限を取得して返すことができましたが、元のクエリが呼び出された後に hibernate が余分なクエリを呼び出すため、効率的ではありません。
詳細版
最初に、エンティティをリンクする方法と、コードがどのように見えるかについて、いくつかの情報を提供しましょう。私の(簡略化された)データベーステーブル構造は次のようになります。
ユーザー.java
@Entity
@Table(name = "user")
public class User {
@Id
@Column(name = "user_id", columnDefinition = "user_id")
private Long userId;
@Transient
private List<String> rights
@ManyToMany
@JoinTable(
name = "user_role",
joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "role_id"))
@JsonIgnore
private List<Role> roles;
//Getters and setters
}
Role.java
@Entity
@Table(name = "role")
public class Role {
@Id
@Column(name = "role_id", columnDefinition = "role_id")
private Long roleId;
@ManyToMany
@JoinTable(
name = "user_role",
joinColumns = @JoinColumn(name = "role_id", referencedColumnName = "role_id"),
inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "user_id"))
@JsonIgnore
private List<Employee> employees;
@ManyToMany
@JoinTable(
name = "role_right",
joinColumns = @JoinColumn(name = "role_id", referencedColumnName = "role_id"),
inverseJoinColumns = @JoinColumn(name = "right_id", referencedColumnName = "right_id"))
@JsonIgnore
private List<Right> rights;
//Getters and setters
}
右.java
@Entity
@Table(name = "right")
public class Right {
@Id
@Column(name = "right_id", columnDefinition = "right_id")
private Long rightId;
@Column(name = "name", columnDefinition = "name")
private String name;
@ManyToMany
@JoinTable(
name = "role_right",
joinColumns = @JoinColumn(name = "right_id", referencedColumnName = "right_id"),
inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "role_id"))
@JsonIgnore
private List<Role> roles;
//Getters and setters
}
テーブルを結合するために Java 仕様 API を使用していることを知っておくことは重要です。
return (root, query, cb) -> {
query.distinct(true);
Join rolesJoin = root.join("roles", JoinType.LEFT);
Join rightsJoin = rolesJoin.join("rights", JoinType.LEFT);
return cb.conjunction();
};
これにより、正しいクエリが作成されます。
select <columns go here>
from employee user0_
left outer join user_role roles1_ on user0_.user_id=roles1_.user_id
left outer join role role2_ on roles1_.role_id=role2_.role_id
left outer join role_right rights3_ on role2_.role_id=rights3_.role_id
left outer join right right4_ on rights3_.right_id=right4_.right_id
今まですべてが私にはよさそうに見えました。しかし、すべてのロールの名前を取得しようとすると、2 つ以上のクエリ (ページと元のクエリのカウント) が実行されています。
//The original code uses lambda for this
for(Role role : user.getRoles()){
for(Right right: role.getRights()){
user.addRight(right.getName());
}
}
追加のクエリは次のようになります。
select <column stuff>
from role_right rights0_
inner join right right1_ on rights0_.right_id=right1_.right_id
where rights0_.role_id=?
これにより、通話が非常に非効率になります。この場合は 1 人のユーザーですが、複数のユーザーの場合は加算されます。
余分なクエリの実行を追加せずに、1 つのクエリですべての権限の名前をユーザー エンティティに配置する方法はありますか?
これまでに試したこと:
@SecondaryTable
User エンティティの Right テーブルから列を直接定義するために使用します。最初に Role を User にリンクしてから、Role テーブルのフィールドを使用して Right テーブルをリンクすることができませんでした。したがって、最終的には、 User オブジェクトの上に @SecondaryTable アノテーションを付け、その下に Right オブジェクトの列を定義する必要があります。User エンティティで使用
@Formula
して、ネイティブ呼び出しをクエリに挿入します。注釈がすべてを権利のリストにマップする方法を理解していなかったため、これも機能しませんでした。
ここには他のオプションがあるかもしれません。または、上記のものを実装する際に何かひどく間違ったことをしました。しかし、今のところ、問題の解決策を見つけるためにどちらの方法をとるべきかわかりません。誰かが私に言うことができれば、それは素晴らしいことです.
前もってありがとう、
ロビン