编辑。在扩展基本存储库类并添加insert方法的同时,一个更优雅的解决方案似乎是在实体中实现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对象的复合主键,所以我不能使用基础spring
FindOne(ID id)方法
在春季JPA中,有没有一种干净的方法可以做到这一点?
我以前使用spring /
Hibernate和我自己的基本存储库创建了一个不带jpa存储库的测试服务。我实现了一个Insert方法和Save方法,如下所示。
这似乎工作正常。使用的save方法getSession().saveOrUpdate
给出了我现在正在体验的内容,并且正在更新现有行。
使用插入方法getSession().save
失败,并需要重复的主键。
@Override
public Order save(Order bean) {
getSession().saveOrUpdate(bean);
return bean;
}
@Override
public Order insert(Order bean) {
getSession().save(bean);
return bean;
}
基于Spring文档的1.3.2章,此处 http://docs.spring.io/spring-
data/jpa/docs/1.4.1.RELEASE/reference/html/repositories.html
可能不是最有效的,因为我们正在执行附加检索以在插入之前检查行的存在,但这是主键。
扩展存储库以添加除保存之外的insert方法。这是第一次切。
我必须将密钥传递给插入以及实体。 我可以避免吗?
我实际上不希望返回数据。 这个entitymanager没有一个exist方法(是否存在,只是做一个count(*)检查一行是否存在?)
import java.io.Serializable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
/**
*
* @author Martins
*/
@NoRepositoryBean
public interface IBaseRepository <T, ID extends Serializable> extends JpaRepository<T, ID> {
void insert(T entity, ID id);
}
实现:定制存储库基类。注意:如果我沿这条路线走,将会创建一个自定义的异常类型。
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 BaseRepositoryImpl<T, ID extends Serializable>
extends SimpleJpaRepository<T, ID> implements IBaseRepository<T, ID> {
private final EntityManager entityManager;
public BaseRepositoryImpl(Class<T> domainClass, EntityManager em) {
super(domainClass, em);
this.entityManager = em;
}
public BaseRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, 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 BaseRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable>
extends JpaRepositoryFactoryBean<R, T, I> {
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new BaseRepositoryFactory(entityManager);
}
private static class BaseRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory {
private EntityManager entityManager;
public BaseRepositoryFactory(EntityManager entityManager) {
super(entityManager);
this.entityManager = entityManager;
}
protected Object getTargetRepository(RepositoryMetadata metadata) {
return new BaseRepositoryImpl<T, I>((Class<T>) metadata.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)
实现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()
导入java.io.Serializable; 导入javax.persistence.Column;
导入javax.persistence.EmbeddedId; 导入javax.persistence.Entity;
导入javax.persistence.Table; 导入javax.xml.bind.annotation.XmlRootElement;
导入org.springframework.data.domain.Persistable;
@Entity
@Table(name = "MTHSEQ")
@XmlRootElement
public class Sequence extends BaseEntity implements Serializable, Persistable<SequencePK> {
private static final long serialVersionUID = 1L;
@EmbeddedId
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,因为您可以看到此ID具有复合PK。
我以前从未做过,但是稍加修改可能会完成任务。
Persistable
实体有一个接口。它具有一种方法boolean isNew()
,在实施时将用于“评估”实体是否为数据库中的新实体。根据该决定,在您从调用之后,EntityManager应该决定调用该实体.merge()
或.persist()
对该实体进行调用。.save()``Repository
这样,如果您实现isNew()
始终返回true,.persist()
则不应将称为,然后应引发错误。
如我错了请纠正我。不幸的是,我现在无法在实时代码上对其进行测试。
Persistable
:[http]( http://docs.spring.io/spring-
问题内容: 我有一个简单的测试,尝试在其中更新对象,但是合并似乎在执行插入操作而不是更新操作。 } 这是我的更新方法 更新代码 现在,我收到以下错误无法提交JPA事务;嵌套的异常是javax.persistence.RollbackException:标记为rollbackOnly的事务 问题答案: 我有一个版本列,当种子数据插入数据库时未设置该列。因此,所有有关更新和删除的问题
问题内容: 我正在使用Oracle 11GR2,并且当varchar2字段为空时,在空字段上执行a 将显示在我的Eclipse控制台上。如何让它显示空字符串呢? 问题答案: 你的getter方法:
嗨,我是Spring Data JPA的新手,我想知道即使我将Id传递给实体,Spring data jpa也是插入而不是合并的。我想当我实现持久接口并实现这两个方法时: 它将自动合并而不是持久化。 我有一个名为User like的实体类: 再上一节课 我有一个名为UserRepostory的自定义存储库,它扩展了JpaReopistory。当我看到实现演示SpringDataJpa使用以上两种方
我有一个模型 视图定位对象: 然后它会做出一些改变(或者可能不会) 然后它尝试保存任何更改: 这里是Django尝试插入另一行而不是更新的地方,导致了一个DB错误 解决方案中有一种类似的问题: 一旦我将primary_key字段设置为自动字段,问题就消失了。 但是,我的主键已经是一个自动字段。 所以我用调试器逐步浏览了django代码,并在文件中资助了这个: 似乎如果没有更改(因此更新不做任何事情
问题内容: 我有一个产品对象,它属于某些类别,即经典的多对一关系。 我想插入和更新产品而不预先选择类别。像这样: 要么 是否可以在不选择类别的情况下进行更新和插入?我不想为此使用HQL或直接查询。 问题答案: session.load()专门用于此类情况。以下: 不会打数据库。但是,如果没有提供给定ID的类别,它将在稍后阶段(刷新期间或多或少)引发异常。 使用速度快且没有副作用(级联等)。
问题内容: 情况 : 我有一个具有java.util.Date类型变量的可持久类: DB中的对应表: 然后,将我的Period对象保存到DB: 之后,如果我尝试从数据库中提取对象,则使用时间戳记类型的变量startDate返回该对象-我尝试使用equals(…)的所有位置均返回false。 问题 :是否有任何方法可以强制Hibernate以java.util.Date类型的对象(而不是Timest