本文是在Spring Data风格中使用Hibernate Natural ID(@NaturalId)的快速实用指南。
我们将主要通过典型的Spring数据存储库揭示Hibernate,bySimpleNaturalId()和byNaturalId()方法,并把它们准确称之为众所周知的,findAll(),findOne()等等。
实现
首先,让我们关注所需类的实现。完成所有这些后,我们将能够为具有自然ID的实体提供存储库。
用自然ID编写实体
让我们考虑以下具有自动生成ID和自然ID(code列)的实体。这只是一个使用一个自然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;
// getters and setters
@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());
}
@Override
public int hashCode() {
return Objects.hash(getCode());
}
@Override
public String toString() {
return "Product{" + "id=" + id + ", name=" + name + ", code=" + code + '}';
}
}
编写NaturalRepository协议
我们首先编写一个名为NaturalRepository的接口。基本上,当我们想要微调存储库时,我们可以依赖 @NoRepositoryBean注释。在我们的例子中,我们想要用另外两个来丰富Spring Data方法库, findBySimpleNaturalId()和findByNaturalId() :
@NoRepositoryBean
public interface NaturalRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
// use this method when your entity has a single field annotated with @NaturalId
Optional<T> findBySimpleNaturalId(ID naturalId);
// use this method when your entity has more than one field annotated with @NaturalId
Optional<T> findByNaturalId(Map<String, Object> naturalIds);
}
编写NaturalRepository实现
此外,我们扩展了SimpleJpaRepository 类并实现了NaturalRepository。在扩展SimpleJpaRepository中,我们可以通过添加我们需要的方法来定制基本存储库。我们主要是扩展了特定于持久性技术的存储库基类,并将此扩展用作存储库代理的自定义基类:
@Transactional(readOnly = true)
public class NaturalRepositoryImpl<T, ID extends Serializable>
extends SimpleJpaRepository<T, ID> implements NaturalRepository<T, ID> {
private final EntityManager entityManager;
public NaturalRepositoryImpl(JpaEntityInformation entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager);
this.entityManager = entityManager;
}
@Override
public Optional<T> findBySimpleNaturalId(ID naturalId) {
Optional<T> entity = entityManager.unwrap(Session.class)
.bySimpleNaturalId(this.getDomainClass())
.loadOptional(naturalId);
return entity;
}
@Override
public Optional<T> findByNaturalId(Map<String, Object> naturalIds) {
NaturalIdLoadAccess<T> loadAccess
= entityManager.unwrap(Session.class).byNaturalId(this.getDomainClass());
naturalIds.forEach(loadAccess::using);
return loadAccess.loadOptional();
}
}
将NaturalRepositoryImpl设置为基类
接下来,我们必须指示Spring Data依赖于我们的自定义存储库基类。在Java配置中,您可以通过@EnableJpaRepositories注释使用repositoryBaseClass属性来执行此操作 :
@SpringBootApplication
@EnableJpaRepositories(repositoryBaseClass = NaturalRepositoryImpl.class)
public class NaturalIdApplication {
...
}