编辑.虽然扩展基础存储库类并添加插入方法可以使更优雅的解决方案似乎在实体中实现Persistable.见可能的解决方案2
我正在使用springframework.data.jpa创建一个服务,使用Hibernate作为ORM,使用JpaTransactionManager.
遵循本教程的基础.
http://www.petrikainulainen.net/spring-data-jpa-tutorial/
我的实体存储库扩展了org.springframework.data.repository.CrudRepository
我正在使用遗留数据库,该数据库使用有意义的主键而不是自动生成的ID
这种情况不应该真的发生,但是由于测试中的错误我遇到了它.订单表具有OrderNumber(M000001等)的有意义的键.主键值在代码中生成,并在保存之前分配给对象.旧数据库不使用自动生成的ID密钥.
我有一个创建新订单的交易.由于存在错误,我的代码生成了一个已存在于数据库中的订单号(M000001)
执行repository.save会导致更新现有订单.我想要的是强制插入并由于重复的主键导致事务失败.
我可以在每个存储库中创建一个Insert方法,在执行保存之前执行查找,如果存在行则执行失败.某些实体具有带有OrderLinePK对象的复合主键,因此我无法使用基本弹簧FindOne(ID id)方法
在春季JPA中有这样一种干净的方法吗?
我之前使用spring / Hibernate和我自己的基础库创建了一个没有jpa存储库的测试服务.我实现了Insert方法和Save方法,如下所示.
这似乎工作正常.
使用getSession().saveOrUpdate的save方法给出了我现在正在经历的现有行更新.
使用getSession()的insert方法.使用重复的主键保存失败,如我所愿.
@Override
public Order save(Order bean) {
getSession().saveOrUpdate(bean);
return bean;
}
@Override
public Order insert(Order bean) {
getSession().save(bean);
return bean;
}
可能的解决方案1
基于这里的春季文档的1.3.2章
http://docs.spring.io/spring-data/jpa/docs/1.4.1.RELEASE/reference/html/repositories.html
可能不是最有效的,因为我们正在进行额外的检索以检查插入之前行的存在,但它是主键.
除了save之外,还扩展存储库以添加插入方法.这是第一次削减.
我必须将密钥传递给插入以及实体.我可以避免这个吗?
我实际上并不想要返回数据. entitymanager没有exists方法(确实存在只需要计数(*)来检查行的存在吗?)
import java.io.Serializable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.norepositoryBean;
/**
*
* @author Martins
*/
@norepositoryBean
public interface IBaseRepository
实现:自定义存储库基类.
注意:如果我沿着这条路线走下去,将会创建一个自定义异常类型.
import java.io.Serializable;
import javax.persistence.EntityManager;
import org.springframework.data.jpa.repository.support.JpaEntityinformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.transaction.annotation.Transactional;
public class BaseRepositoryImplinformationinformation,EntityManager entityManager) {
super (entityinformation,entityManager);
this.entityManager = entityManager;
}
@Transactional
public void insert(T entity,ID id) {
T exists = entityManager.find(this.getDomainClass(),id);
if (exists == null) {
entityManager.persist(entity);
}
else
throw(new IllegalStateException("duplicate"));
}
}
自定义存储库工厂bean
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryfactorybean;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import javax.persistence.EntityManager;
import java.io.Serializable;
/**
* This factory bean replaces the default implementation of the repository interface
*/
public class BaseRepositoryfactorybeanfactorybeanMetadata Metadata) {
return new BaseRepositoryImplMetadata.getDomainType(),entityManager);
}
protected Class> getRepositoryBaseClass(RepositoryMetadata Metadata) {
// The RepositoryMetadata can be safely ignored,it is used by the JpaRepositoryFactory
//to check for QueryDslJpaRepository's which is out of scope.
return IBaseRepository.class;
}
}
}
最后在配置中连接自定义存储库基类
// Define this class as a Spring configuration class
@Configuration
// Enable Spring/jpa transaction management.
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = {"com.savant.test.spring.donorservicejpa.dao.repository"},repositoryBaseClass = com.savant.test.spring.donorservicejpa.dao.repository.BaseRepositoryImpl.class)
可能的解决方案2
遵循patrykos91的建议
为实体实现Persistable接口并覆盖isNew()
import java.io.Serializable;
import javax.persistence.MappedSuperclass;
import javax.persistence.PostLoad;
import javax.persistence.PostPersist;
import javax.persistence.PostUpdate;
@MappedSuperclass
public abstract class BaseEntity implements Serializable{
protected transient boolean persisted;
@PostLoad
public void postLoad() {
this.persisted = true;
}
@PostUpdate
public void postUpdate() {
this.persisted = true;
}
@PostPersist
public void postPersist() {
this.persisted = true;
}
}
然后每个实体必须实现isNew()和getID()
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlRootElement;
import org.springframework.data.domain.Persistable;
@Entity
@Table(name = "MTHSEQ")
@XmlRootElement
public class Sequence extends BaseEntity implements Serializable,PersistablebeddedId
protected SequencePK sequencePK;
@Column(name = "NEXTSEQ")
private Integer nextseq;
public Sequence() {
}
@Override
public boolean isNew() {
return !persisted;
}
@Override
public SequencePK getId() {
return this.sequencePK;
}
public Sequence(SequencePK sequencePK) {
this.sequencePK = sequencePK;
}
public Sequence(String mthkey,Character centre) {
this.sequencePK = new SequencePK(mthkey,centre);
}
public SequencePK getSequencePK() {
return sequencePK;
}
public void setSequencePK(SequencePK sequencePK) {
this.sequencePK = sequencePK;
}
public Integer getNextseq() {
return nextseq;
}
public void setNextseq(Integer nextseq) {
this.nextseq = nextseq;
}
@Override
public int hashCode() {
int hash = 0;
hash += (sequencePK != null ? sequencePK.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// Todo: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Sequence)) {
return false;
}
Sequence other = (Sequence) object;
if ((this.sequencePK == null && other.sequencePK != null) || (this.sequencePK != null && !this.sequencePK.equals(other.sequencePK))) {
return false;
}
return true;
}
@Override
public String toString() {
return "com.savant.test.spring.donorservice.core.entity.Sequence[ sequencePK=" + sequencePK + " ]";
}
}
抽象出isNew()会很好,但我认为不行. getId不能作为实体具有不同的Id,因为您可以看到这个具有复合PK.
实体有一个Persistable接口.它有一个方法boolean isNew(),它在实现时将用于“评估”实体是否在数据库中是新的.根据该决定,在您从Repository调用.save()之后,EntityManager应决定在该实体上调用.merge()或.persist().
顺便说一句,如果你实现isNew()总是返回true,那么.persist()应该被称为no mater what,并且应该抛出错误.
如我错了请纠正我.不幸的是,我现在无法在实时代码上测试它.
原文地址:https://www.jb51.cc/spring/432376.html
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。