这是一个Spring Boot应用程序案例,展示如何使用Hibernate映射自然业务键 @NaturalId。
关键点:
1.在实体(例如,Product)中,标记应作为自然ID 的属性(业务键) @NaturalId; 通常,实体中只有一个这样的属性,但是这里也支持多个属性。
@Entity public class Product implements Serializable {
private static final long serialVersionUID = 1L;
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
private String name;
@NaturalId(mutable = false) @Column(nullable = false, updatable = false, unique = true, length = 50) private String code;
// @NaturalId(mutable = false) // @Column(nullable = false, updatable = false, unique = true) // private Long sku;
|
对于不可变的id,将列标记为@NaturalId(mutable = false)和@Column(nullable = false, updatable = false, unique = true, ...)
对于可变id,将列标记为@NaturalId(mutable = true)和 @Column(nullable = false, updatable = true, unique = true, ...)
2. 使用自然id覆盖equals()和hashCode()
@Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof Product)) { return false; } Product naturalIdProduct = (Product) o; return Objects.equals(getCode(), naturalIdProduct.getCode()); // including sku // return Objects.equals(getCode(), naturalIdProduct.getCode()) // && Objects.equals(getSku(), naturalIdProduct.getSku()); }
@Override public int hashCode() { return Objects.hash(getCode()); // including sku // return Objects.hash(getCode(), getSku()); }
@Override public String toString() { return "Product{" + "id=" + id + ", name=" + name + ", code=" + code + '}'; // including sku // return "Product{" + "id=" + id + ", name=" + name + ", code=" + code + ", sku=" + sku + '}'; }
|
3. 定义一个@NoRepositoryBean接口(例如NaturalRepository)来定义两个名为findBySimpleNaturalId()and的方法findByNaturalId()
@NoRepositoryBean public interface NaturalRepository<T, NID extends Serializable> {
// use this method when your entity has a single field annotated with @NaturalId Optional<T> findBySimpleNaturalId(NID naturalId); // use this method when your entity has more than one field annotated with @NaturalId Optional<T> findByNaturalId(Map<String, Object> naturalIds); }
|
4. 提供此接口的实现(例如,一个NaturalRepositoryImpl实现 )依赖于Hibernate的Session实现 bySimpleNaturalId(),和 byNaturalId()方法
@Repository @Transactional(readOnly = true) public abstract class NaturalRepositoryImpl<T, NID extends Serializable> implements NaturalRepository<T, NID> {
@PersistenceContext private EntityManager entityManager;
private final Class<T> entityClass;
public NaturalRepositoryImpl(Class<T> entityClass) { this.entityClass = entityClass; }
@Override public Optional<T> findBySimpleNaturalId(NID naturalId) {
Optional<T> entity = entityManager.unwrap(Session.class) .bySimpleNaturalId(entityClass) .loadOptional(naturalId);
return entity; }
@Override public Optional<T> findByNaturalId(Map<String, Object> naturalIds) {
NaturalIdLoadAccess<T> loadAccess = entityManager.unwrap(Session.class).byNaturalId(entityClass); naturalIds.forEach(loadAccess::using);
return loadAccess.loadOptional(); }
}
|
对于实体,编写扩展的存储库类(例如,用于Product实体写入 ProductNaturalRepository)NaturalRepositoryImpl并使用它来设置实体类类型和自然id类型(当实体使用多个自然ID时,类型不再相关,只需将其设置为Serializable)
45 在您的服务中注入此类并调用findBySimpleNaturalId()或 findByNaturalId()
源代码可在此处获得。