OneToOne主要使用在存在一一对应的业务场景下,例如将一个用户信息拆分为了2个部分:基本信息和扩展信息;在这种场景下,就需要进行OneToOne的映射使用。
用户信息将被分拆为2个部分: 基本信息和扩展信息.
基本信息包括:id,name, location, 所购产品
扩展信息:level(用户级别), discountRate折扣率,remark备注等信息
他们之间是一一对应的关系,都从属于user这个实体类。
UserEntity.java类的定义:
/**
* User DAO.
* @author xxx
* @date 2019-05-04
*/
@EqualsAndHashCode(callSuper = true)
@Table(name="t_user")
@Entity
@Data
@EntityListeners(AuditingEntityListener.class)
public class UserEntity extends BaseEntity {
@Column
private String name;
@Column
private String location;
/**
* Who owns the foreign Key, who will be the owner, and declare the JoinColumn.
*
*/
@JsonManagedReference
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name="user_ext_id", referencedColumnName = "id")
private UserExtEntity userExtEntity;
}
UserExtEntity.java用户扩展信息定义如下:
/**
* 用户的扩展信息.
* @author xxx
* @date 2019/05/03
*
*/
@Table(name="t_user_ext")
@Entity
@Data
@EntityListeners(AuditingEntityListener.class)
public class UserExtEntity extends BaseEntity {
//用户级别
@Column
private Integer level;
/**
* 折扣率
*/
@Column(name="discount_rate")
private Float discountRate;
/**
* 用户备注
*/
@Column
private String remark;
@JsonBackReference
@OneToOne(cascade = {CascadeType.REFRESH},
mappedBy = "userExtEntity", fetch = FetchType.LAZY)
private UserEntity user;
}
User DAO之UserRepsoitory.java:
/ * DAO
*
* @author: xxx
* @date: 2019/05/03
*/
@Repository
public interface UserRepository extends JpaRepository {
}
UserExt DAO之UserExtRepository.java:
/**
* User Ext Repository
*
* @author xxx
* @date 2019-05-05
*/
@Repository
public interface UserExtRepository extends JpaRepository {
}
BaseEntity.java 几类定义:
@Data
@MappedSuperclass
public class BaseEntity implements java.io.Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@CreatedDate
@Column(name="created_time")
private Date createdTime;
@LastModifiedDate
@Column(name="updated_time")
private Date updatedTime;
@CreatedBy
@Column(name="created_by")
private String createdBy;
@LastModifiedBy
@Column(name="last_modified_by")
private String lastModifiedBy;
@Version
private Integer version;
}
封装结果数据类,ResultData.java:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ResultData {
private Integer code;
private String message;
private Object data;
public static ResultData failure() {
ResultData resultData = ResultData.builder().code(-1).message("failure").build();
return resultData;
}
public static ResultData success() {
ResultData resultData = ResultData.builder().code(0).message("success").build();
return resultData;
}
}
Controller层的测试代码如下:
@RestController
@Slf4j
public class UserController {
@Autowired
private UserRepository userRepo;
@Autowired
private UserExtRepository extRepo;
@GetMapping("/case1")
public ResultData testCreate() {
UserEntity user = new UserEntity();
user.setName("zhangsan");
user.setLocation("BeiJing");
UserExtEntity userExtEntity = new UserExtEntity();
userExtEntity.setDiscountRate(0.9f);
userExtEntity.setLevel(1);
userExtEntity.setRemark("remark info");
user.setUserExtEntity(userExtEntity);
user = this.userRepo.save(user);
log.info("User:{}", user);
ResultData resultData = ResultData.success();
resultData.setData(user);
return resultData;
}
}
在postman中直接调用这些链接进行测试,然后进入到数据库中进行数据检查数据是否存在。
其表示1对1的数据对应关系,主要是基于表的数据关系。
在@OneToOne注解的映射关系中,如果需要定义双向映射关系,其中定义了外键约束的表中外键字段,其所对应的Entity属性为hosted(主),其另外Entity类中定义为从属关系。
在本示例中,将user_ext_id定义在了UserEntity对应的t_user表中,则UserEntity中的userExtEntity字段为hosted(主),在UserExtEntity定义的user属性则为从属。
从另外一个维度来观察,定义了JoinColumn的字段为hosted字段,host字段与JoinColumn是紧密相关的。
cascade属性定义了数据操作之时的同步类型,其涵盖了CURD以及游离态:
public enum CascadeType {
/** Cascade all operations */
ALL,
/** Cascade persist operation */
PERSIST,
/** Cascade merge operation */
MERGE,
/** Cascade remove operation */
REMOVE,
/** Cascade refresh operation */
REFRESH,
/**
* Cascade detach operation
*
* @since Java Persistence 2.0
*
*/
DETACH
}
fetch其表示当前Entity的数据是否提前加载,eager表示其预加载,在Entity创建之时,即从数据库中拉取加载。Lazy表示只有在真正访问该数据字段时,才从数据库中进行加载拉取。
public enum FetchType {
/** Defines that data can be lazily fetched. */
LAZY,
/** Defines that data must be eagerly fetched. */
EAGER
}
mappedBy字段表示当前字段为ORM映射中的从属字段,其从属于mappedBy中的值。在示例中是userExtEntity,这个属性定义在UserEntity中。
由于在ORM中的双向依赖会存在循环依赖的关系,所以在进行结果输出之时,会出现无限的循环直至异常报错,对于此类问题,该如何处理呢?
基于@JsonManagedReference,@JsonBackReference进行Json双向映射中的循环依赖管理,解决映射的问题。
@JsonManagedReference is the forward part of reference – the one that gets serialized normally. 前项部分,用于正常的序列化操作。
@JsonBackReference is the back part of reference – it will be omitted from serialization.
后项部分,这部分的内容将在序列化中被忽略。
在本文中,通过一个相对完成的示例展示了对于OneToOne映射的基本用法,在其中包含了@OneToOne、@JoinColumn、@JsonManagedReference和@JsonBackReference的用法,大家多多体会其中用法。