我有一个具有复合键的实体,我试图通过将spring数据jpa存储库用于mysql数据库来保持它,如下所示:
@Embeddable
public class MobileVerificationKey implements Serializable{
private static final long serialVersionUID = 1L;
@Column(name="CUSTOMERID")
private Long customerId;
@Column(name="CUSTOMERTYPE")
private Integer customerType;
@Column(name="MOBILE")
private Long mobile;
@Embeddable
public class MobileVerificationKey implements Serializable{
private static final long serialVersionUID = 1L;
@Column(name="CUSTOMERID")
private Long customerId;
@Column(name="CUSTOMERTYPE")
private Integer customerType;
@Column(name="MOBILE")
private Long mobile;
//getter and setters
}
实体为
@Entity
@Table(name="mobileverificationdetails")
public class MobileVerificationDetails {
@EmbeddedId
private MobileVerificationKey key;
@Column(name="MOBILETYPE")
private String mobileType;
@Column(name="MOBILEPIN")
private Integer mobilePin;
//getters and setters
}
我的spring数据jpa存储库看起来像这样:
public interface MobileVerificationDetailsRepository extends
CrudRepository<MobileVerificationDetails, MobileVerificationKey> {
@Override
MobileVerificationDetails save(MobileVerificationDetails mobileVerificationDetails);
@Override
MobileVerificationDetails findOne(MobileVerificationKey id);
}
现在,如果我尝试为原始记录添加重复记录,为其他字段添加不同的值。当我尝试插入第二条记录时,会导致使用新值更新现有记录,而不是因为违反主键而抛出异常约束......任何人都可以解释一下这种行为。
答案 0 :(得分:3)
解决这个问题的最简单(也是最少侵入性)的方法可能是确保id只在persist之前设置。这可以通过@PrePersist
回调来实现:
abstract class MobileVerificationDetails {
@EmbeddedId
private MobileVerificationKey id;
@PrePersist
void initIdentifier() {
if (id == null) {
this.id = … // Create ID instance here.
}
}
}
除此之外,您可以通过实施persist(…)
并相应地实施Persistable
来强制执行isNew()
。确保此方法在第一次插入时返回true
。我们通常会看到人们持有一个瞬态布尔标志,该标志在@PostPersist
/ @PostLoad
带注释的方法中更新。
abstract class AbstractEntity<ID extends Serializable> implements Persistable<ID> {
private @Transient boolean isNew = true;
@Override
public boolean isNew() {
return isNew;
}
@PostPersist
@PostLoad
void markNotNew() {
this.isNew = false;
}
}
答案 1 :(得分:1)
Spring Data Jpa Repository功能是通过包含以下save(..)方法的SimpleJpaRepository类实现的:
@Transactional
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
因此,Spring Jpa Data Repository save(...)方法合并了一个已存在的实体。
与此相反,如果使用已存在的实体调用,则裸EntityManager#persist()会抛出异常。
可以通过向Spring Data Repository / ies添加custom behavior来解决问题。可以使用1.3.1 Adding custom behavior to single repositories中example here或1.3.2 Adding custom behavior to all repositories中example here中所述的方法之一添加自定义行为。在这两种情况下,自定义行为都包括委托给EntityManager#persist()的新persist()方法。请注意,在方法1.3.2中。你已经拥有一个EntityManager实例,在方法1.3.1中你可以使用@PersistenceContext注入EntityManager实例。
反对我的评论,我建议在存储库中添加新方法,而不是覆盖现有的保存(...)。