如何检索此 Hibernate @ManyToOne 关系中记录的所有 children?

How can I retrieve all the children of a record in this Hibernate @ManyToOne relation?

我正在使用 Spring Data JPA 和 Hibernate 映射开发 Spring 引导项目。我对如何实现以下查询有以下疑问。

我有一个 User 实体 class 是这样的:

@Entity
@Table(name = "portal_user")
@Getter
@Setter
public class User implements Serializable {
     
    private static final long serialVersionUID = 5062673109048808267L;
    
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;
    
    @Column(name = "first_name")
    @NotNull(message = "{NotNull.User.firstName.Validation}")
    private String firstName;
    
    @Column(name = "middle_name")
    private String middleName;
    
    @Column(name = "surname")
    @NotNull(message = "{NotNull.User.surname.Validation}")
    private String surname;
    
    @Column(name = "sex")
    @NotNull(message = "{NotNull.User.sex.Validation}")
    private char sex;
    
    @Column(name = "birthdate")
    @NotNull(message = "{NotNull.User.birthdate.Validation}")
    private Date birthdate;
    
    @Column(name = "tax_code")
    @NotNull(message = "{NotNull.User.taxCode.Validation}")
    private String taxCode;
    
    @Column(name = "e_mail")
    @NotNull(message = "{NotNull.User.email.Validation}")
    private String email;
    
    @Column(name = "pswd")
    @NotNull(message = "{NotNull.User.pswd.Validation}")
    private String pswd;
    
    @Column(name = "contact_number")
    @NotNull(message = "{NotNull.User.contactNumber.Validation}")
    private String contactNumber;
    
    @Temporal(TemporalType.DATE)
    @Column(name = "created_at")
    private Date createdAt;
    
    @Column(name = "is_active")
    private boolean is_active;
    
    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval = true)
    @JsonManagedReference
    private Set<Address> addressesList = new HashSet<>();
    
    @ManyToMany(cascade = { CascadeType.MERGE })
    @JoinTable(
        name = "portal_user_user_type", 
        joinColumns = { @JoinColumn(name = "portal_user_id_fk") }, 
        inverseJoinColumns = { @JoinColumn(name = "user_type_id_fk") }
    )
    Set<UserType> userTypes;


    @ManyToOne(fetch = FetchType.EAGER)
    @JsonProperty("subagent")
    private User parent;

    public User() {
        super();
    }


    public User(String firstName, String middleName, String surname, char sex, Date birthdate, String taxCode,
            String email, String pswd, String contactNumber, Date createdAt, boolean is_active) {
        super();
        this.firstName = firstName;
        this.middleName = middleName;
        this.surname = surname;
        this.sex = sex;
        this.birthdate = birthdate;
        this.taxCode = taxCode;
        this.email = email;
        this.pswd = pswd;
        this.contactNumber = contactNumber;
        this.createdAt = createdAt;
        this.is_active = is_active;
    }
    

}

这个 class 的实例代表我系统的用户。一个用户可以有一个特定的parent(这个概念类似于推荐的概念:一个用户可以在系统中带来另一个用户)。这是由 ManyToOne 递归关系处理的:

@ManyToOne(fetch = FetchType.EAGER)
@JsonProperty("subagent")
private User parent;

基本上一个用户包含的是parent(将him\her带入平台)。它工作正常。因此检索用户我可以很容易地检索谁是它的 parent 的信息(它包含在检索到的用户 object 中)。

现在我需要实现相反的行为:我必须定义一个从 parent 开始检索其所有 children.

的“查询”

之前的用户实体class映射以下数据库table:

荧光笔parent_id包含定义这个递归关系的FK。所以它包含另一个用户的 PK,即 parent.

我有这个 UserRepository 存储库接口(它扩展了 JpaRepository 接口)

public interface UsersRepository extends JpaRepository<User, Integer> {
    
    User findByemail(String email);
    
    List<User> findByUserTypes_TypeName(String typeName);

}

如您所见,我使用的是“按方法查询”样式。是否有可能使用“按方法查询”样式实现这样的行为? (如果 JPQL 也可以)

你可以做到

List<User> findByParent_Id(Integer id);

或者你可以这样做

@Query("SELECT u FROM User u WHERE u.id = ?1")
List<User> getReferredUsers(Integer id);

用户与 parent 之间的关系在给定代码中是单向的。通过使其成为双向的,可以很容易地以任何一种方式查询数据。

参考下面的代码使其成为双向的。还要确保相关的 FetchType 以避免性能风险。这里 FetchType.LAZY 用于一对多关联,因此它在需要时使用代理引用查询数据。

@ManyToOne(fetch = FetchType.EAGER)
    @JsonProperty("subagent")
    @JsonBackReference
    private User parent;
    
    @JsonManagedReference
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "parent")
    private Set<User> userSet = new HashSet<>();

Child 实体仅在使用 parent.getUserSet 时获取,因为 FetchType.Lazy

 public Set<User> getUsers(int id) {
       User parent = userRepository.getById(id);
        return parent.getUserSet();
    }