Hibernate @WhereJoinTable Annotation – Hibernate @WhereJoinTable注释

最后修改: 2019年 10月 8日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Using an Object Relational Mapping tool, like Hibernate, makes it easy to read our data into objects, but can make forming our queries difficult with complex data models.

使用对象关系映射工具,如Hibernate,可以很容易地将我们的数据读成对象,但对于复杂的数据模型,会使我们的查询难以形成。

The many-to-many relationship is always challenging, but it can be more challenging when we wish to acquire related entities based on some property of the relation itself.

多对多的关系总是具有挑战性,但是当我们希望根据关系本身的某些属性来获取相关实体时,它可能更具挑战性。

In this tutorial, we are going to look at how to solve this problem using Hibernate’s @WhereJoinTable annotation.

在本教程中,我们将看看如何使用Hibernate的@WhereJoinTable注解来解决这个问题。

2. Basic @ManyToMany Relation

2.基本@ManyToMany关系

Let’s start with a simple @ManyToMany relationship. We’ll need domain model entities, a relation entity, and some sample test data.

让我们从一个简单的@ManyToMany关系开始。我们需要领域模型实体、一个关系实体和一些测试数据样本。

2.1. Domain Model

2.1.领域模型

Let’s imagine we have two simple entities, User and Group, which are associated as @ManyToMany:

让我们想象一下,我们有两个简单的实体,UserGroup,它们被关联为@ManyToMany:

@Entity(name = "users")
public class User {

    @Id
    @GeneratedValue
    private Long id;
    private String name;

    @ManyToMany
    private List<Group> groups = new ArrayList<>();

    // standard getters and setters

}
@Entity
public class Group {

    @Id
    @GeneratedValue
    private Long id;
    private String name;

    @ManyToMany(mappedBy = "groups")
    private List<User> users = new ArrayList<>();

    // standard getters and setters

}

As we can see, our User entity can be a member of more than one Group entity. Similarly, a Group entity can contain more than one User entity.

我们可以看到,我们的User实体可以是一个以上的Group实体的成员。同样地,一个Group实体可以包含一个以上的User实体。

2.2. Relation Entity

2.2.关系实体

For @ManyToMany associations, we need a separate database table called a relation table. The relation table needs to contain at least two columns: The primary keys of the related User and Group entities.

对于@ManyToMany关联,我们需要一个单独的数据库表,称为关系表。关系表需要至少包含两个列。相关的UserGroup实体的主键。

With only the two primary key columns, our Hibernate mapping can represent this relation table.

只有两个主键列,我们的Hibernate映射可以表示这个关系表

However, if we need to put additional data in the relation table, we should also define a relation entity for the many-to-many relationship itself.

然而,如果我们需要在关系表中放入额外的数据,我们也应该为多对多关系本身定义一个关系实体。

Let’s create UserGroupRelation class to do this:

让我们创建UserGroupRelation类来做这个。

@Entity(name = "r_user_group")
public class UserGroupRelation implements Serializable {

    @Id
    @Column(name = "user_id", insertable = false, updatable = false)
    private Long userId;

    @Id
    @Column(name = "group_id", insertable = false, updatable = false)
    private Long groupId;

}

Here we’ve named the entity r_user_group so we can reference it later.

在这里,我们将实体命名为r_user_group,以便我们以后可以引用它。

For our extra data, let’s say we want to store every User‘s role for each Group. So, we’ll create UserGroupRole enumeration:

对于我们的额外数据,假设我们想存储每个User对每个Group的角色。因此,我们将创建UserGroupRole枚举。

public enum UserGroupRole {
    MEMBER, MODERATOR
}

Next, we’ll add a role property to UserGroupRelation:

接下来,我们将向UserGroupRelation:添加一个role属性。

@Enumerated(EnumType.STRING)
private UserGroupRole role;

Finally, to configure it properly, we need to add the @JoinTable annotation on User‘s groups collection. Here we’ll specify the join table name using r_user_group, the entity name of UserGroupRelation:

最后,为了正确配置,我们需要在Usergroups集合上添加@JoinTable注释。在这里,我们将使用r_user_group来指定连接表的名称,UserGroupRelation的实体名称:

@ManyToMany
@JoinTable(
    name = "r_user_group",
    joinColumns = @JoinColumn(name = "user_id"),
    inverseJoinColumns = @JoinColumn(name = "group_id")
)
private List<Group> groups = new ArrayList<>();

2.3. Sample Data

2.3.样本数据

For our integration tests, let’s define some sample data:

对于我们的集成测试,让我们定义一些样本数据。

public void setUp() {
    session = sessionFactory.openSession();
    session.beginTransaction();
    
    user1 = new User("user1");
    user2 = new User("user2");
    user3 = new User("user3");

    group1 = new Group("group1");
    group2 = new Group("group2");

    session.save(group1);
    session.save(group2);

    session.save(user1);
    session.save(user2);
    session.save(user3);

    saveRelation(user1, group1, UserGroupRole.MODERATOR);
    saveRelation(user2, group1, UserGroupRole.MODERATOR);
    saveRelation(user3, group1, UserGroupRole.MEMBER);

    saveRelation(user1, group2, UserGroupRole.MEMBER);
    saveRelation(user2, group2, UserGroupRole.MODERATOR);
}

private void saveRelation(User user, Group group, UserGroupRole role) {

    UserGroupRelation relation = new UserGroupRelation(user.getId(), group.getId(), role);
    
    session.save(relation);
    session.flush();
    session.refresh(user);
    session.refresh(group);
}

As we can see, user1 and user2 are in two groups. Also, we should notice that while user1 is MODERATOR on group1, at the same time it has a MEMBER role on group2.

我们可以看到,user1user2在两个组。另外,我们应该注意到,虽然user1group1上是moderator,但同时它在group2上有一个MEMBER角色。

3. Fetching @ManyToMany Relations

3.取出@ManyToMany关系

Now we’ve properly configured our entities, let’s fetch the groups of the User entity.

现在我们已经正确配置了我们的实体,让我们来获取User实体的组。

3.1. Simple Fetch

3.1 简单获取

In order to fetch groups, we can simply invoke the getGroups() method of User inside an active Hibernate session:

为了获取组,我们可以简单地在一个活动的Hibernate会话中调用UsergetGroups()方法。

List<Group> groups = user1.getGroups();

Our output for groups will be:

我们对群组的输出将是。

[Group [name=group1], Group [name=group2]]    

But how can we get the groups of a user whose group role is only MODERATOR?

但是,我们怎样才能获得一个用户的组别,而这个用户的组别角色只是MODERATOR?

3.2. Custom Filters on a Relation Entity

3.2.关系实体上的自定义过滤器

We can use the @WhereJoinTable annotation to directly acquire only filtered groups.

我们可以使用@WhereJoinTable注解来直接只获取过滤的组。

Let’s define a new property as moderatorGroups and put the @WhereJoinTable annotation on it. When we access the related entities via this property, it will only contain groups of which our user is MODERATOR.

让我们定义一个新的属性为moderatorGroups,并给它加上@WhereJoinTable注释。当我们通过这个属性访问相关实体时,它将只包含我们的用户是MODERATOR.的组。

We’ll need to add a SQL where clause to filter the groups by the MODERATOR role:

我们需要添加一个SQL where子句,通过MODERATOR 角色过滤组。

@WhereJoinTable(clause = "role='MODERATOR'")
@ManyToMany
@JoinTable(
    name = "r_user_group",
    joinColumns = @JoinColumn(name = "user_id"),
    inverseJoinColumns = @JoinColumn(name = "group_id")
)
private List<Group> moderatorGroups = new ArrayList<>();

Thus, we can easily get the groups with the specified SQL where clause applied:

因此,我们可以很容易地得到应用了指定SQL where子句的组。

List<Group> groups = user1.getModeratorGroups();

Our output will be the groups on which the user has only the role of MODERATOR:

我们的输出将是用户只拥有MODERATOR:角色的组。

[Group [name=group1]]

4. Conclusion

4.总结

In this tutorial, we learned how to filter @ManyToMany collections based on a property of the relation table using Hibernate’s @WhereJoinTable annotation.

在本教程中,我们学习了如何使用Hibernate的@WhereJoinTable注解根据关系表的一个属性过滤@ManyToMany集合。

As always, all the code samples given in this tutorial are available over on GitHub.

一如既往,本教程中给出的所有代码样本都可以在GitHub上获得