龙空技术网

SpringDataJPA中实体关联映射OneToOne

捡着六便士仰望月亮 108

前言:

现时我们对“注解onetomany”大体比较珍视,咱们都需要知道一些“注解onetomany”的相关知识。那么小编在网上搜集了一些关于“注解onetomany””的相关内容,希望兄弟们能喜欢,我们一起来了解一下吧!

SpringDataJPA中实体关联映射OneToOne

JPA中关联关系的映射,是映射关系中比较复杂的一种映射关系,概括起来说来有一对一、一对多和多对多几种关系。细分起来他们又有单向和双向之分。今天我们详细地介绍一下OneToOne关系的具体实现和各种属性设置带来的影响。

一、默认单向OneToOne

我们有两个实体User 和 UserExtra,在User 中使用OneToOne 关联UserExtra。代码如下:

package com.xtoad.ecms.baseinfo.model;import com.xtoad.ecms.common.web.base.BaseModel;import org.hibernate.annotations.Table;import org.springframework.data.jpa.domain.support.AuditingEntityListener;import javax.persistence.CascadeType;import javax.persistence.Column;import javax.persistence.ConstraintMode;import javax.persistence.Entity;import javax.persistence.EntityListeners;import javax.persistence.FetchType;import javax.persistence.ForeignKey;import javax.persistence.JoinColumn;import javax.persistence.JoinTable;import javax.persistence.ManyToMany;import javax.persistence.OneToOne;import java.util.List;/** * 用户实体类 * * @author xtoad * @date 2020/05/29 */@Entity@Table(appliesTo = "user", comment = "用户表")@EntityListeners(AuditingEntityListener.class)public class User extends BaseModel {    private static final long serialVersionUID = -1616905035103332302L;    /**     * 用户扩展信息     */    @OneToOne    private UserExtra userExtra;    /**     * 获取 用户扩展信息     */    public UserExtra getUserExtra() {        return this.userExtra;    }    /**     * 设置 用户扩展信息     */    public void setUserExtra(UserExtra userExtra) {        this.userExtra = userExtra;    }        /////////////////忽略其他属性和方法,完整代码请参照文末的git地址}
package com.xtoad.ecms.baseinfo.model;import com.xtoad.ecms.baseinfo.enums.Sex;import com.xtoad.ecms.common.web.base.BaseModel;import org.hibernate.annotations.Table;import org.springframework.data.jpa.domain.support.AuditingEntityListener;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.EntityListeners;import javax.persistence.EnumType;import javax.persistence.Enumerated;import javax.persistence.Temporal;import javax.persistence.TemporalType;import java.util.Date;/** * 用户扩展信息实体类 * * @author xtoad * @date 2020/05/29 */@Entity@Table(appliesTo = "user_extra", comment = "用户扩展信息表")@EntityListeners(AuditingEntityListener.class)public class UserExtra extends BaseModel {    private static final long serialVersionUID = 4833292279765547874L;    /**     * 姓名     */    @Column(length = 100, columnDefinition = "VARCHAR(100) COMMENT '姓名'")    private String name;    /**     * 生日     */    @Temporal(TemporalType.DATE)    @Column(columnDefinition = "DATE COMMENT '生日'")    private Date birthday;    /**     * 性别     */    @Column(nullable = false, length = 10, columnDefinition = "VARCHAR(10) COMMENT '性别'")    @Enumerated(EnumType.STRING)    private Sex sex;    /**     * 默认构造函数     */    public UserExtra() {    }    /**     * 获取 姓名     */    public String getName() {        return this.name;    }    /**     * 设置 姓名     */    public void setName(String name) {        this.name = name;    }    /**     * 获取 生日     */    public Date getBirthday() {        return this.birthday;    }    /**     * 设置 生日     */    public void setBirthday(Date birthday) {        this.birthday = birthday;    }    /**     * 获取 性别     */    public Sex getSex() {        return this.sex;    }    /**     * 设置 性别     */    public void setSex(Sex sex) {        this.sex = sex;    }    @Override    public String toString() {        return "UserExtra{" +                "name='" + name + '\'' +                ", birthday=" + birthday +                ", sex=" + sex +                "} " + super.toString();    }}

我们看生成的表结构:

并且生成了外键:

扩展表则没有任何变化:

下面我们修改一下关联注解,让生成的关联字段不生成外键,并且指定关联实体的加载方式和级联修改方式:

    /**     * 用户扩展信息     */    @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)    @JoinColumn(nullable = false, foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))    private UserExtra userExtra;

我们再生成看一下两张表结构无变化,只是User表中的外键消失了:

我们来插入数据和测试数据试试:

/* * Copyright  2019-2029  联通集团财务有限公司版权所有 */package com.xtoad.ecms.baseinfo.service.impl;import com.xtoad.ecms.baseinfo.enums.Sex;import com.xtoad.ecms.baseinfo.model.User;import com.xtoad.ecms.baseinfo.model.UserExtra;import com.xtoad.ecms.baseinfo.repository.IProductRepository;import com.xtoad.ecms.baseinfo.repository.IShoeRepository;import com.xtoad.ecms.baseinfo.repository.IUserExtraRepository;import com.xtoad.ecms.baseinfo.repository.IUserRepository;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import java.util.Date;/** * 用户实体测试类 * * @author xtoad * @date 2021/3/3 */@SpringBootTestpublic class UserTest {    @Autowired    private IUserRepository userRepository;    @Autowired    private IUserExtraRepository userExtraRepository;    @Test    void saveUser() {        User user = new User();        user.setLoginNo("Junit5_user");        user.setPhone("13456781234");        user.setEmail("13456781234@test.com");        user.setPassword("123");        UserExtra userExtra = new UserExtra();        userExtra.setBirthday(new Date());        userExtra.setSex(Sex.MALE);        userExtra.setName("单元测试用户01");        user.setUserExtra(userExtra);        userRepository.save(user);    }}

结果:

我们看一下执行日志:

[11:42:40.499] DEBUG org.hibernate.engine.transaction.internal.TransactionImpl 53 <init> - On TransactionImpl creation, JpaCompliance#isJpaTransactionComplianceEnabled == false[11:42:40.500] DEBUG org.hibernate.engine.transaction.internal.TransactionImpl 81 begin - begin[11:42:40.596] DEBUG org.hibernate.engine.spi.ActionQueue 281 addResolvedEntityInsertAction - Executing identity-insert immediately[11:42:40.608] DEBUG org.hibernate.engine.jdbc.spi.SqlStatementLogger 127 logStatement -     insert     into        user_extra        (create_time, create_user, last_update_time, last_update_user, birthday, name, sex)     values        (?, ?, ?, ?, ?, ?, ?)Hibernate:     insert     into        user_extra        (create_time, create_user, last_update_time, last_update_user, birthday, name, sex)     values        (?, ?, ?, ?, ?, ?, ?)[11:42:40.635] DEBUG org.hibernate.id.IdentifierGeneratorHelper 78 getGeneratedIdentity - Natively generated identity: 2[11:42:40.636] DEBUG org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl 106 release - HHH000387: ResultSet's statement was not registered[11:42:40.645] DEBUG org.hibernate.engine.spi.ActionQueue 281 addResolvedEntityInsertAction - Executing identity-insert immediately[11:42:40.646] DEBUG org.hibernate.engine.jdbc.spi.SqlStatementLogger 127 logStatement -     insert     into        user        (create_time, create_user, last_update_time, last_update_user, email, login_no, nick_name, password, phone, user_extra_id)     values        (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)Hibernate:     insert     into        user        (create_time, create_user, last_update_time, last_update_user, email, login_no, nick_name, password, phone, user_extra_id)     values        (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)[11:42:40.648] DEBUG org.hibernate.id.IdentifierGeneratorHelper 78 getGeneratedIdentity - Natively generated identity: 1[11:42:40.649] DEBUG org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl 106 release - HHH000387: ResultSet's statement was not registered[11:42:40.650] DEBUG org.hibernate.engine.transaction.internal.TransactionImpl 98 commit - committing[11:42:40.652] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener 139 prepareEntityFlushes - Processing flush-time cascades[11:42:40.654] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener 192 prepareCollectionFlushes - Dirty checking collections[11:42:40.662] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener 113 logFlushResults - Flushed: 0 insertions, 0 updates, 0 deletions to 2 objects[11:42:40.662] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener 120 logFlushResults - Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections[11:42:40.664] DEBUG org.hibernate.internal.util.EntityPrinter 110 toString - Listing entities:[11:42:40.669] DEBUG org.hibernate.internal.util.EntityPrinter 117 toString - com.xtoad.ecms.baseinfo.model.UserExtra{birthday=Wed Mar 03 11:42:40 CST 2021, createTime=Wed Mar 03 11:42:40 CST 2021, sex=MALE, name=单元测试用户01, lastUpdateUser=anonymous, createUser=anonymous, id=2, lastUpdateTime=Wed Mar 03 11:42:40 CST 2021}[11:42:40.670] DEBUG org.hibernate.internal.util.EntityPrinter 117 toString - com.xtoad.ecms.baseinfo.model.User{password=123, createTime=Wed Mar 03 11:42:40 CST 2021, phone=13456781234, userExtra=com.xtoad.ecms.baseinfo.model.UserExtra#2, nickName=null, roles=null, lastUpdateUser=anonymous, createUser=anonymous, id=1, loginNo=Junit5_user, email=13456781234@test.com, lastUpdateTime=Wed Mar 03 11:42:40 CST 2021}

会先执行user_extra的插入,再执行user的插入。

二、双向OneToOne

在User类中添加userExtra属性:

    /**     * 用户扩展信息     */    @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "user")    private UserExtra userExtra;

在UserExtra中添加user 属性:

    /**     * 用户信息     */    @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)    private User user;

我们再看一下生成的表结构:

这种场景一定会生成外键。并且关联的id 会生成在mappedBy 指定的属性所在的实体类的表中。

此时维护端就变成了UserExtra实体类。

标签: #注解onetomany