JPA加入特定领域

JPA Join on specific field

我有这种情况:

User 及其相关的 UserRole 实体 classes,如下所示:

@Entity
@Table(name="USER")
public class User implements Serializable {

   @Id
   @GeneratedValue(strategy=GenerationType.AUTO)
   @Column(name="ID", unique=true, nullable=false)
   private int id;

   @Column(name="USERNAME", unique=true, nullable=false, length=255)
   private String username;

   @OneToMany(mappedBy="user")
   private List<UserRole> userRoles;
}

@Entity
@Table(name="user_roles")
public class UserRole implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="user_role_id", unique=true, nullable=false)
    private int userRoleId;

    @Column(nullable=false, length=45)
    private String role;

    @ManyToOne
    @JoinColumn(name="username", nullable=false)
    private User user;
}

现在,我需要查询所有具有特定角色的用户。我正在尝试加入 JPA 规范,就像这样:

Join<User, UserRole> join = root.join(User_.userRoles);
Expression<String> match = join.get(UserRole_.role);                    
Predicate predicate = builder.equal(match, "ROLE_USER");

问题是生成的join会在User.id和UserRole.username之间,查询显然没有结果.

select count(user0_.ID) as col_0_0_ from USER user0_ inner join
user_roles userroles1_ on user0_.ID=userroles1_.username where 
userroles1_.role='ROLE_USER'

我需要在 username 字段上同时使用 on 子句:

... from USER user0_ inner join
    user_roles userroles1_ on user0_.USERNAME=userroles1_.username ...

我注意到 Join class who:

.on 方法

Modify the join to restrict the result according to the specified ON condition. Replaces the previous ON condition, if any. Return the join object

这是正确的做法吗?如果是这样,我该如何实施?

Join<User, UserRole> join = root.join(User_.userRoles).on(????);

提前谢谢你。

更新UserRole_ 元模型 class

@StaticMetamodel(UserRole.class)
public class UserRole_ {
    public static volatile SingularAttribute<UserRole, Integer> userRoleId;
    public static volatile SingularAttribute<UserRole, String> role;
    public static volatile SingularAttribute<UserRole, User> user;
}

User_ 元模型 class:

@StaticMetamodel(User.class)
public class User_ {
    public static volatile SingularAttribute<User, Integer> id;
    public static volatile SingularAttribute<User, String> username;
    public static volatile ListAttribute<User, UserRole> userRoles;
}

再次检查一下user_roles.username列包含的内容,因为默认情况下,它包含引用实体的@Id列,这里引用的实体是User,它的@Id列是 id(在您的架构中:ID)而不是 username(在您的架构中:USERNAME)。

不过,这里有一个如何编写您在此处描述的内容的示例:

The problem is that the generated join will be between User.id and UserRole.username and the query will obviously have no results. I need instead to have the on clause both on username fields:

在 JPQL 中(使用 JPA 2.1)

// get entity manager as 'em'
TypedQuery<User> q = em.createQuery("SELECT u FROM User u INNER JOIN UserRole ur ON ur.user = u.username WHERE ur.role = 'ROLE_USER'", User.class);
List<User> results = q.getResultList();

你需要使用referencedColumnName:

@ManyToOne
@JoinColumn(name="username", referencedColumnName="username", nullable=false)
private User user;

只有 @JoinColumn(name="username") 你告诉 Hibernate user_roles 中的连接列被命名为 username - 但它仍然期望它包含 @Id 属性 的用户。如果您为您的模式创建 DDL,您将看到 Hibernate 为 user_roles.username.

生成一个数字列