我正在使用 hibernate 4 作为 jpa 提供程序。在我的代码中,我插入一个新版本的报告(到 PactRegister),选择该报告的所有版本,删除子记录(ActRegister),并通过插入子记录计算当前活动的报告版本。但是对于相同的父记录,删除子项并插入子项的操作会引发异常。怎么了?
而且我有一条错误消息(已删除的对象将被级联重新保存):
ru.sigmasoft.DoMessage.Factory.State.OracleProcess.OracleSenderHandler.handle(OracleSenderHandler.java:73)
at ru.sigmasoft.DoMessage.Factory.State.OracleProcess.OracleProcessingTemplate.process(OracleProcessingTemplate.java:63)
at ru.sigmasoft.DoMessage.Oracle.OracleTableListenerImpl.onMessage(OracleTableListenerImpl.java:28)
at ru.sigmasoft.DoMessage.Oracle.OracleTableConsumer.listen(OracleTableConsumer.java:68)
at ru.sigmasoft.DoMessage.Oracle.OracleTableConsumer.setMessageListener(OracleTableConsumer.java:35)
at ru.DbManage.run(DbManage.java:22)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.IllegalArgumentException: org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations): [ru.sigmasoft.DOSrv.Server.domain.VersionSchema.ActRegister#49]
at org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:882)
at ru.sigmasoft.DOSrv.Server.service.jpa.oraDb.Repository_PactRegister.modify(Repository_PactRegister.java:53)
at ru.sigmasoft.DOSrv.Server.service.bean.Registration.Registration_Act.registerDocumentVersion(Registration_Act.java:62)
at ru.sigmasoft.Specification.Message.CMN13011_Handler.handle(CMN13011_Handler.java:74)
at ru.sigmasoft.DoMessage.Factory.State.OracleProcess.ParseBody.handle(ParseBody.java:107)
at ru.sigmasoft.DoMessage.Factory.State.OracleProcess.OracleProcessingTemplate.process(OracleProcessingTemplate.java:46)
... 5 more
Caused by: org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations): [ru.sigmasoft.DOSrv.Server.domain.VersionSchema.ActRegister#49]
at org.hibernate.internal.SessionImpl.forceFlush(SessionImpl.java:1222)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:177)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:136)
at org.hibernate.ejb.event.EJB3MergeEventListener.saveWithGeneratedId(EJB3MergeEventListener.java:71)
at org.hibernate.event.internal.DefaultMergeEventListener.saveTransientEntity(DefaultMergeEventListener.java:236)
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:216)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:154)
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:910)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:892)
at org.hibernate.engine.spi.CascadingAction$6.cascade(CascadingAction.java:288)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
at org.hibernate.event.internal.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:439)
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsPersistent(DefaultMergeEventListener.java:183)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:157)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:76)
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:900)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:884)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:888)
at org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:879)
我的实体:
@Entity
@Table(name = "PACT_REGISTER")
@XmlRootElement
public class PactRegister implements Serializable {
private static final long serialVersionUID = 1L;
// @Max(value=?) @Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
@Id
@GenericGenerator(name = "generatorPactR", strategy = "foreign",
parameters =
@Parameter(name = "property", value = "edRegister"))
@GeneratedValue(generator = "generatorPactR")
@Basic(optional = false)
@Column(name = "ID")
private Long id;
@Column(name = "G071")
private String g071;
@Column(name = "G072")
@Temporal(TemporalType.DATE)
private Date g072;
@Column(name = "G073")
private String g073;
@Column(name = "G073K")
private String g073k;
@Column(name = "SVHLICK")
private String svhlick;
@Column(name = "SVHLIC")
private String svhlic;
@Column(name = "MODIFICATIONDATETIME")
@Temporal(TemporalType.DATE)
private Date modificationdatetime;
@JoinColumn(name = "ID", referencedColumnName = "ID", insertable = false, updatable = false)
@OneToOne(optional = false, fetch = FetchType.LAZY)
private EdRegister edRegister;
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true , mappedBy = "pactRegister", fetch = FetchType.LAZY)
private ActRegister actRegister;
public PactRegister() {
}
public PactRegister(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getG071() {
return g071;
}
public void setG071(String g071) {
this.g071 = g071;
}
public Date getG072() {
return g072;
}
public void setG072(Date g072) {
this.g072 = g072;
}
public String getG073() {
return g073;
}
public void setG073(String g073) {
this.g073 = g073;
}
public String getG073k() {
return g073k;
}
public void setG073k(String g073k) {
this.g073k = g073k;
}
public String getSvhlick() {
return svhlick;
}
public void setSvhlick(String svhlick) {
this.svhlick = svhlick;
}
public String getSvhlic() {
return svhlic;
}
public void setSvhlic(String svhlic) {
this.svhlic = svhlic;
}
public Date getModificationdatetime() {
return modificationdatetime;
}
public void setModificationdatetime(Date modificationdatetime) {
this.modificationdatetime = modificationdatetime;
}
public EdRegister getEdRegister() {
return edRegister;
}
public void setEdRegister(EdRegister edRegister) {
this.edRegister = edRegister;
}
public ActRegister getActRegister() {
return actRegister;
}
protected void setActRegister(ActRegister actRegister) {
this.actRegister = actRegister;
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.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 PactRegister)) {
return false;
}
PactRegister other = (PactRegister) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return "Eh_OWNER.PactRegister[ id=" + id + " ]";
}
public void removeFromActive(final ActRegister ar) {
// check for no-op
if (ar == null /*|| !getActRegister().contains(ar)*/) {
return;
}
// dissociate arg
// actRegister=null;
this.setActRegister(null);
ar.setPactRegister(null);
// additional business logic
//onRemoveFromActive(ar);
}
public void addToActive(final ActRegister ar) {
// check for no-op
if (ar == null /*|| !getActRegister().contains(ar)*/) {
return;
}
// dissociate arg
// actRegister=null;
setActRegister(ar);
ar.setPactRegister(this);
// additional business logic
//onRemoveFromActive(ar);
}
and
@Entity
@Table(name = "ACT_REGISTER")
@XmlRootElement
public class ActRegister implements Serializable {
private static final long serialVersionUID = 1L;
// @Max(value=?) @Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
@Id
@GenericGenerator(name = "generatorActR", strategy = "foreign",
parameters =
@Parameter(name = "property", value = "pactRegister"))
@GeneratedValue(generator = "generatorActR")
@Basic(optional = false)
@Column(name = "ID")
private Long id;
@JoinColumn(name = "ID", referencedColumnName = "ID", insertable = false, updatable = false)
@OneToOne(optional = false, fetch = FetchType.LAZY)
private PactRegister pactRegister;
public ActRegister() {
}
public ActRegister(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public PactRegister getPactRegister() {
return pactRegister;
}
public void setPactRegister(PactRegister pactRegister) {
this.pactRegister = pactRegister;
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.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 ActRegister)) {
return false;
}
ActRegister other = (ActRegister) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return "Eh_OWNER.ActRegister[ id=" + id + " ]";
}
}
我的存储库:
public class Repository_PactRegister extends GenericRepositoryImpl<PactRegister, Long> {
public Repository_PactRegister(EntityManager em) {
super(em);
}
public List<PactRegister> findActive(String g071, Date g072, String g073, String g073k, String svhLick, String svhLic) {
String SELECT_ACTIVE = "select * from PACT_REGISTER a inner join ACT_REGISTER b on a.id=b.id \n"
+ " where a.g071=:G071 and a.g072=:G072 and a.g073=:G073 and a.g073k=:G073K and a.SVHLICK=:SVHLICK and a.SVHLIC=:SVHLIC";
Query q = em.createNativeQuery(SELECT_ACTIVE, PactRegister.class);
q.setParameter("G071", g071);
q.setParameter("G072", g072, TemporalType.DATE);
q.setParameter("G073", g073);
q.setParameter("G073K", g073k);
q.setParameter("SVHLICK", svhLick);
q.setParameter("SVHLIC", svhLic);
q.setParameter("SVHLIC", svhLic);
List<PactRegister> results = q.getResultList();
return results;
}
public PactRegister findLastByDocIdentifyer(String g071, Date g072, String g073, String g073k, String svhLick, String svhLic) {
//Поиск записи с максимальной датой модификации для данного отчета
String SELECT_MAX = "select * from PACT_REGISTER f where f.id=(select max(id) \n"
+ " from PACT_REGISTER a)";
Query q = em.createNativeQuery(SELECT_MAX, PactRegister.class);
List<PactRegister> results = q.getResultList();
return results.isEmpty() ? null : results.get(0);
}
@Override
public PactRegister modify(PactRegister entity) {
em.find(PactRegister.class, entity.getId());
PactRegister mergedPactRegister = em.merge(entity);
return mergedPactRegister;
}
}
逻辑:下一个动作在一个事务中执行:
private final Repository_EdRegister rer;
private final Repository_PactRegister rpr;
......
public PactRegister registerDocumentVersion(Act doc, EdRegister edRegister) {
//insert new record of report
PactRegister pactRegister = new PactRegister();
pactRegister.setG071(doc.getG071());
pactRegister.setG072(doc.getG072());
pactRegister.setG073(doc.getG073());
pactRegister.setG073k("0"/*doc.getG073k()*/);
pactRegister.setSvhlick(doc.getSvhlick());
pactRegister.setSvhlic(doc.getSvhlic());
pactRegister.setModificationdatetime(new Date()/*doc.getModificationdatetime()*/);//Lkz ncnbhjdfybz!!
edRegister.addToPactRegister(pactRegister);
rpr.create(pactRegister);
// Get parent records for this report
List<PactRegister> activeS = rpr.findActive(doc.getG071(), doc.getG072(), doc.getG073(), /*doc.getG073k()*/ "0", doc.getSvhlick(), doc.getSvhlic());
//remove all childs
if (pactRegister != null) {
for (PactRegister active : activeS) {
ActRegister ar = active.getActRegister();
active.removeFromActive(ar);
// ar = null;
rpr.modify(active);
}
}
//Choose active record
// PactRegister activeCandidate = rpr.findById(PactRegister.class, Long.valueOf("110"));
PactRegister activeCandidate = rpr.findLastByDocIdentifyer(doc.getG071(), doc.getG072(), doc.getG073(), "0"/*doc.getG073k()*/, doc.getSvhlick(), doc.getSvhlic());
activeCandidate.addToActive(new ActRegister());
rpr.modify(activeCandidate);
return activeCandidate;
}Exception throws when transaction commit. And only if execute method rpr.findLastByDocIdentifyer (it's call
String SELECT_MAX = "select * from PACT_REGISTER f where f.id=(select max(id) \n"
+ " from PACT_REGISTER a)";
Query q = em.createNativeQuery(SELECT_MAX, PactRegister.class);
List<PactRegister> results = q.getResultList();
return results.isEmpty() ? null : results.get(0);
)