首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >这个Hibernate实体类映射是如何实现同一DB表上的递归关系的?

这个Hibernate实体类映射是如何实现同一DB表上的递归关系的?
EN

Stack Overflow用户
提问于 2022-01-05 23:26:42
回答 1查看 169关注 0票数 0

我正在使用Spring和Hibernate映射开发Spring门户,并且我在试图理解由其他人实现的以下代码时遇到了一些困难(它运行得很好,但是JPA\Hibernate不是我的茶,我遗漏了一些东西)。

在数据库中,我有一个表示应用程序用户的portal_user表。

如您所见,此表包含parent_id字段,该字段是portal_user表本身的FK。这用于在用户与其父用户之间创建递归关系(您可以看到这是一种典型的参考关系:父用户是将另一个用户引入系统的用户)。

portal_user DB表映射到此用户实体类上:

代码语言:javascript
复制
@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();
        // TODO Auto-generated constructor stub
    }


    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;
    }
    

}

特别是,这一关系似乎是由这个领域处理的:

代码语言:javascript
复制
@ManyToOne(fetch = FetchType.EAGER)
@JsonProperty("subagent")
private User parent;

然后,我使用这个服务方法将一个新对象插入到portal_user表中,同时考虑到可以设置parent_id字段:

代码语言:javascript
复制
@Override
@Transactional
public User insertClientUser(User clientUser) throws DuplicateException, SubAgentUserNotExist, NotFoundException {
    String subAgentEmail = null;
    if(clientUser.getParent() != null) subAgentEmail = clientUser.getParent().getEmail();

    User checkClientUserExist = this.getUserByemail(clientUser.getEmail());

    if (checkClientUserExist != null) {
        String MsgErr = String.format("User %s already registered in the system !!! "
                + "Impossible to use POST", clientUser.getEmail());

        log.warning(MsgErr);

        throw new DuplicateException(MsgErr);
    }

    log.info(String.format("UserServiceImpl --> insertClientUser client user: %s %s - subagent email: %s ", 
             clientUser.getFirstName(), clientUser.getSurname(), subAgentEmail));

    // check if present because we could add a user without assigned subagent
    if(subAgentEmail != null) {

        User subAgentUser = this.getUserByemail(subAgentEmail);

        if (subAgentUser == null) {
            String errorMessage = String.format("Subagent user %s doesn't exist in the sistem !!! "
                    + "Impossible to use POST", subAgentEmail);

            log.warning(errorMessage);

            throw new SubAgentUserNotExist(errorMessage);
        }

        clientUser.setParent(subAgentUser);
    }
    
    User insertedClientUser = userRepository.save(clientUser);
    
    return insertedClientUser;
}

注意:subAgentUser客户端是我作为portal_user DB表的新记录插入的用户,而客户端是尚未存在于此DB表中的用户,它将是我插入的用户的父级。因此,基本上,在我的portal_user表上,我将有一个新记录(客户机用户),它具有包含子代理用户ID的parent_id

这个方法的工作原理非常简单:

  1. 检查必须插入的当前用户是否不存在于portal_user表中。如果用户尚不存在于表中,则意味着必须插入该用户。

  1. 检索调用另一个服务方法的子代理用户(),并将其设置为我们要插入的客户端用户的属性。

最后,

  1. 将此客户端用户保存到portal_user DB表.

中。

好的,这一切都很有效,但是我不明白Hibernate是如何正确地设置这个新插入方法的parent_id字段的值的。这个parent_id字段包含父对象(检索的parent_id对象)的PK。

如果我在执行前一个服务方法之后探索我的portal_user表,我就会发现我所期望的:

最后一行是插入的对象。如您所见,parent_id FK字段的值为53,即相同表中预期父用户的PK。

它很好,但我不明白它是怎么回事。谁说冬眠如何设置这个FK的值?特别是,我是confuserd,因为似乎没有将该字段显式映射到我的用户实体类中,实际上我有:

代码语言:javascript
复制
@ManyToOne(fetch = FetchType.EAGER)
@JsonProperty("subagent")
private User parent;

那我错过了什么?它到底是怎么工作的?

EN

回答 1

Stack Overflow用户

发布于 2022-01-06 06:17:29

在Hibernate中,@ManyToOne为另一个具有多重性的实体类指定了一个单值关联。在这种情况下,它与同一实体相关联。

ORM将数据从对象模型映射到关系模型,反之亦然。因此,这些关系是使用实体映射的。这有助于我们轻松地从父对象遍历到子对象。我们可以构建多个嵌套关系,可以通过使用点和链接方法遍历来查询或创建对象。

众所周知,每个实体都有自己的生命周期,一旦设置了关联,Hibernate就会将外键映射为关联实体的主标识符。在这里,它分配给id列,这是一个主键。但是,可以使用@JoinColumn注释对其进行定制。

下面是Hibernate在创建portal_user表以设置关联之后生成的sql。

代码语言:javascript
复制
alter table portal_user 
       add constraint FKdgqt4pnsjho6u58mtnackj4h8 
       foreign key (parent_id) 
       references portal_user

当subAgentUser实体设置为clientUser时,hibernate使用parent_id列将记录映射到关联实体(SubAgentUser)的主要标识符,同时刷新查询.

代码语言:javascript
复制
 clientUser.setParent(subAgentUser);
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70600779

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档