我有一个问题,需要执行完全删除然后插入。 试过一种方法,可以建议还有其他更好的方法吗?
{
"incidentTime": 1491207083634,
"estCode": 152,
"incidentParamTrans": [
{
"paramValueList": [
11,
12,
14
]
}
]
}
这是主要的实体类。
@Entity
@Table(name="IR_TB_INCIDENT_HDR")
public class IncidentHdr implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(name="IR_TB_INCIDENT_HDR_INCIDENTID_GENERATOR", sequenceName="IR_SEQ_INCIDENT_ID")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="IR_TB_INCIDENT_HDR_INCIDENTID_GENERATOR")
@Column(name="INCIDENT_ID")
private long incidentId;
@OneToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE, CascadeType.REMOVE}, fetch = FetchType.LAZY, mappedBy="incidentHdr")
private Set<IncidentParamTran> incidentParamTrans;
public IncidentHdr() {
}
}
这是具有一对多映射的实体类。其中DTO(来自请求json)中的paramValueList被提取并作为3(paramId)记录插入IncidentParamTrans表。
/**
* The persistent class.
*
*/
@Entity
@Table(name="IR_TB_INCIDENT_PARAM_TRAN")
public class IncidentParamTran implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(name="IR_TB_INCIDENT_PARAM_TRAN_GENERATOR", sequenceName="IR_SEQ_INCIDENT_PARAM_RUN_ID")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="IR_TB_INCIDENT_PARAM_TRAN_GENERATOR")
@Column(name="PARAM_RUN_ID")
private long paramRunId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="INCIDENT_ID")
private IncidentHdr incidentHdr;
@Column(name="PARAM_ID")
private BigDecimal paramId;
public IncidentParamTran() {
}
}
如果输入是这样的话。
{
"incidentId": 4700,
"incidentTime": 1491207083634,
"estCode": 152,
"incidentParamTrans": [
{
"paramValueList": [
10,
14,
]
}
]
}
必须删除IncidentParamTrans表中的所有数据,事件ID为4700.其中事件ID不是主键。
之后我必须将所有新记录(2条记录)插入IncidentParamTrans。
执行完全删除并执行新插入,这反过来会抛出刷新异常。
我试过的代码
服务层代码段
@Override
@Transactional(rollbackFor=IncidentReportingException.class)
public IncidentHdrDto saveIncidentReport(IncidentHdrDto incidentHdrDto)
if(incidentHdrDto.getIncidentParamTrans()!= null ){
Set<IncidentParamTranDto> incidentParamTranDtos = new HashSet<IncidentParamTranDto>();
// dto.getSensitivityPattern().remove
IncidentHdr inc = mapper.map(incidentHdrDto, IncidentHdr.class);
incidentParamTransRepo.deleteByIncidentHdr(inc);
for(IncidentParamTranDto item:incidentHdrDto.getIncidentParamTrans()){
if(item != null){
for(BigDecimal paramItem: item.getParamValueList()){
IncidentParamTranDto val = new IncidentParamTranDto();
val.setParamId(paramItem);
val.setIncidentHdr(incidentHdrDto);
incidentParamTranDtos.add(val);
}
}
}
incidentHdrDto.setIncidentParamTrans(incidentParamTranDtos);
}
result = saveIncidentHdr(incidentHdrDto);
}
将dto映射到实体并调用repo save方法。
@Override
public IncidentHdrDto saveIncidentHdr(IncidentHdrDto incidentHdrDto)
throws IncidentReportingException {
return mapper.map(iReportingRepo.save(mapper.map(incidentHdrDto, IncidentHdr.class)),IncidentHdrDto.class);
}
Repo class used to delete
public interface IncidentParamTransRepo extends JpaRepository<IncidentParamTran, Long> {
Long deleteByIncidentHdr(IncidentHdr inc);
}
例外:
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: om.gov.moh.irs.model.entity.incident.IncidentHdr
答案 0 :(得分:1)
我认为它失败是因为IncidentHdr.incidentParamTrans
集合仍处于无效状态,因为实际删除事件参数由incidentParamTransRepo.deleteByIncidentHdr(inc);
存储库调用处理,但另一方面所有权结束通过级联行为配置在IncidentHdr.incidentParamTrans
上设置CRUD操作。
为避免混淆,我建议尝试以下方法:
IncidentHdr.incidentParamTrans
集合:inc .getIncidentParamTrans().clear()
IncidentHdr
:incidentHdrRepository.**saveAndFlush**(inc)
。这将触发您使用手动存储库调用执行的删除查询。使用 flush 执行保存非常重要,因此在再次填充集合之前,此时将执行实际的删除查询。这种方法的优点是Hibernate可以跟踪IncidentHdr.incidentParamTrans
集合上完成的所有更改,并确保正确处理状态。
这种方法的一个缺点是它将整个IncidentHdr.incidentParamTrans
集合加载到内存中,但是,根据您的配置,我认为它不应该是一个问题,因为您已经这样做了(通过委派{的CRUD管理{1}} IncidentHdr.incidentParamTrans
实体。
希望这有帮助。