java如何将Hibernate与DtoMapping和@Audited一起使用
我已经审核了具有单向一域映射的父实体和子实体类。我有两个具有相同字段的DTO类(包括id
)和一个从DTO映射到实体的映射器。
如果在DTO类id
字段中设置了Mapper.map(ParentDto parentDto, Parent.class)
方法将不会实例化父实体的新实例,而是根据其id从数据库加载实体,然后映射加载实体上的字段。映射childs
{
我的问题是,在映射child列表之前,映射程序会清除列表->orphanRemoval = true
触发并从数据库中删除子项。然后,它们必须由映射程序重新创建并持久化。为了防止这种情况,我在映射之前在父实体上使用session.detach(parent)
,从而防止对数据库的任何更改,并在稍后通过session.saveOrUpdate(parent)
重新连接它。这导致了NonUniqueObjectException
映射器的工作原理如下:
@Stateless
public class Mapper{
@PersistenceContext(unitName = "core")
private EntityManager em;
public void map(ParentDto parentDto, Parent parent) {
Session session = em.unwrap(Session.class);
if em.contains(parent) {
session.detach(parent); //detach so that orphanRemoval will not delete childs from DB
}
...
parent.getChilds().clear;
for (ChildDto childDto : parentDto.getChilds()) {
parent.getChilds().add(mapToEntity(childDto));
}
session.saveOrUpdate(parent); //(re-)attach, so that changed fields or new childs get written to DB
}
public Parent mapToEntity(ParentDto parentDto) {
Parent parentEntity= null;
if (parentDto.id != null) {
parentEntity= loadParentEntityFromDb(parentDto.id);
}
if (parentEntity= null) {
parentEntity= new Parent();
}
map(parentDto, parentEntity);
return parentEntity;
}
public Child mapToEntity(ChildDto childDto) {
Child childEntity= null;
if (childDto.id != null) {
childEntity= loadChildEntityFromDb(childDto.id);
}
if (childEntity= null) {
childEntity= new Child();
}
map(childDto, childEntity);
return childEntity;
}
}
母公司:
@Entity
@Audited
public class Parent implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
@Getter
private Long id;
...
@Getter
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
@JoinTable(name = "PARENT_TO_CHILD", joinColumns = @JoinColumn(name = "PARENT_ID", referencedColumnName = "ID"), inverseJoinColumns = @JoinColumn(name = "CHILD_ID", referencedColumnName = "ID"))
private final List<Child> childs = new ArrayList<>();
}
和子实体
@Entity
@Audited
public class Child implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
@Getter
private Long id;
...
}
Dto类:
public class ParentDto implements Serializable {
private static final long serialVersionUID = 1L;
@Getter
@Setter
private Long id;
...
@Getter
private final List<ChildDto> childs = new ArrayList<>();
}
public class ChildDto implements Serializable {
private static final long serialVersionUID = 1L;
@Getter
@Setter
private Long id;
...
}
在映射过程中使用此设置,我将获得
12:35:17,422 WARN [com.arjuna.ats.arjuna] (default task-5) ARJUNA012125: TwoPhaseCoordinator.beforeCompletion - failed for SynchronizationImple< 0:ffff0a00100f:4b2caaeb:5e4cf8b3:58b38, org.wildfly.transaction.client.AbstractTransaction$AssociatingSynchronization@1149eaa7 >: org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [PARENT_TO_CHILDS_AUD#{REV=Revision [id=98781, timestamp=1582112117394, username=RUser], Parent_id=885752, childs_id=885754}]
的作用是,如果我使用em.detach(parent)
,然后在映射之后使用em.merge(parent)
。但是merge返回一个持久的父对象的副本,给映射器的parent
保持分离状态。我无法更改映射方法public void map(ParentDto parentDto, Parent parent)
的签名,这就是我首先尝试使用session.saveOrUpdate(parent)
的原因,因为这应该只对给定对象起作用并重新连接它
那么,有没有一种方法可以让@Audit
注释与session.saveOrUpdate()
一起工作,或者防止hibernate在映射过程中删除子项(这些子项在几分之一秒内是孤立的),而无需在映射之前更改列表的清除
我正在使用Hibernate 5.3.6。决赛
共 (0) 个答案