第一步,在实体中标记你的业务字段为@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;
@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 + '}';
}
这里的code字段标记为@NaturalId,注意点:
对于非可变id,将列标记为@NaturalId(mutable = false)和@Column(nullable = false, updatable = false, unique = true, ...)
对于可变id,将列标记为@NaturalId(mutable = true)和@Column(nullable = false, updatable = true, unique = true, ...)
使用NaturalId重写覆盖equals()并hashCode()方法
第二步,需要定义@NoRepositoryBean接口(NaturalRepository),在其中定义两个方法,命名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);
}
第三步, 实现此接口(NaturalRepositoryImpl),其中依赖使用Hibernate, Session, bySimpleNaturalId()和 byNaturalId() 方法。
@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();
}
}
第四步:在SpringBoot入口类中使用@EnableJpaRepositories(repositoryBaseClass = NaturalRepositoryImpl.class)注册此实施为基类
@SpringBootApplication
@EnableJpaRepositories(repositoryBaseClass = NaturalRepositoryImpl.class)
public class NaturalIdApplication {
第五步:对于实体,编写一个经典的存储库:
@Repository
public interface ProductRepository<T, ID> extends NaturalRepository<Product, Long>{
}
第六步:在您的服务中注入此类并调用findBySimpleNaturalId()或findByNaturalId()
@SpringBootApplication
@EnableJpaRepositories(repositoryBaseClass = NaturalRepositoryImpl.class)
public class NaturalIdApplication {
private static final Logger logger = Logger.getLogger(NaturalIdApplication.class.getName());
private final ProductRepository productRepository;
public NaturalIdApplication(ProductRepository productRepository) {
this.productRepository = productRepository;
}
public static void main(String[] args) {
SpringApplication.run(NaturalIdApplication.class, args);
}
@Bean
public ApplicationRunner init() {
return args -> {
// persist two products
Product tshirt = new Product();
tshirt.setName("T-Shirt");
tshirt.setCode("014-tshirt-2019");
// tshirt.setSku(1L);
Product socks = new Product();
socks.setName("Socks");
socks.setCode("012-socks-2018");
// socks.setSku(2L);
productRepository.save(tshirt);
productRepository.save(socks);
Optional<Product> p1 = productRepository.findById(tshirt.getId()); // find by ID
Optional<Product> p2 = productRepository.findBySimpleNaturalId(tshirt.getCode()); // find by natural ID
if (p1.isPresent() && p2.isPresent()) {
System.out.println("p1: " + p1.get());
System.out.println("p2: " + p2.get());
} else {
System.out.println("Not found!");
}
};
}
}
点击标题见原文