OneToOne場景
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;
}
DAO層聲明
User DAO之UserRepsoitory.java:
/ * DAO
*
* @author: xxx
* @date: 2019/05/03
*/
@Repository
public interface UserRepository extends JpaRepository<UserEntity, Long> {
}
UserExt DAO之UserExtRepository.java:
/**
* User Ext Repository
*
* @author xxx
* @date 2019-05-05
*/
@Repository
public interface UserExtRepository extends JpaRepository<UserExtEntity, Long> {
}
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中直接調用這些鏈接進行測試,然後進入到數據庫中進行數據檢查數據是否存在。
分析說明
@OneToOne之主從關係
其表示1對1的數據對應關係,主要是基於表的數據關係。
在@OneToOne註解的映射關係中,如果需要定義雙向映射關係,其中定義了外鍵約束的表中外鍵字段,其所對應的Entity屬性爲hosted(主),其另外Entity類中定義爲從屬關係。
在本示例中,將user_ext_id定義在了UserEntity對應的t_user表中,則UserEntity中的userExtEntity字段爲hosted(主),在UserExtEntity定義的user屬性則爲從屬。
從另外一個維度來觀察,定義了JoinColumn的字段爲hosted字段,host字段與JoinColumn是緊密相關的。
@OneToOne之屬性
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中。
Json轉換中的循環依賴
由於在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的用法,大家多多體會其中用法。