Java 如何将Hibernate与数据映射和@Audited一起使用
我已经审核了具有单向一域映射的父实体和子实体类。我有两个DTO类,它们的字段相同(包括Java 如何将Hibernate与数据映射和@Audited一起使用,java,hibernate,hibernate-envers,Java,Hibernate,Hibernate Envers,我已经审核了具有单向一域映射的父实体和子实体类。我有两个DTO类,它们的字段相同(包括id),还有一个从DTO映射到实体的映射器。 如果在DTO classid字段中设置了Mapper.map(ParentDto ParentDto,Parent.class)方法将不会实例化父实体的新实例,而是根据其id从数据库加载实体,然后映射加载实体上的字段。映射childsMapper.map(ChildDto parentDto,Child.class)方法也会尝试通过其id从数据库加载子对象 我的问题
id
),还有一个从DTO映射到实体的映射器。
如果在DTO classid
字段中设置了Mapper.map(ParentDto ParentDto,Parent.class)
方法将不会实例化父实体的新实例,而是根据其id从数据库加载实体,然后映射加载实体上的字段。映射childs
Mapper.map(ChildDto parentDto,Child.class)
方法也会尝试通过其id从数据库加载子对象
我的问题是,在映射child列表之前,映射程序会清除列表->orphanRemoving=true
触发器并从数据库中删除子项。然后,它们必须由映射程序重新创建并持久化。为了防止这种情况,我在映射之前在父实体上使用了session.detach(parent)
,从而防止对数据库进行任何更改,并在以后通过session.saveOrUpdate(parent)
重新连接数据库。这会导致ununiqueObjectException
映射器的工作原理如下:
@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<>();
}
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;
...
}
public类ParentDto实现可序列化{
私有静态最终长serialVersionUID=1L;
@吸气剂
@塞特
私人长id;
...
@吸气剂
private final List childs=new ArrayList();
}
实现可序列化的公共类childt{
私有静态最终长serialVersionUID=1L;
@吸气剂
@塞特
私人长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}]
12:35:17422警告[com.arjuna.ats.arjuna](默认任务-5)arjuna01225:TwoPhaseCoordinator.before completion-同步失败imple<0:ffff0a00100f:4b2caaeb:5e4cf8b3:58b38,org.wildfly.transaction.client.AbstractTransaction$AssociatingSynchronization@1149eaa7>:org.hibernate.unUniqueObjectException:具有相同标识符值的另一个对象已与会话关联:[PARENT_TO_CHILDS_AUD#{REV=Revision[id=98781,timestamp=1582112394,username=RUser],PARENT_id=885752,CHILDS_id=885754}]
的作用是使用em.detach(parent)
,然后在映射em.merge(parent)
之后使用。但是merge返回一个持久的父对象的副本,提供给映射器的父对象保持分离。我无法更改映射方法public void map(ParentDto ParentDto,Parent Parent)
的签名,这就是为什么我首先尝试使用session.saveOrUpdate(Parent)
,因为这应该只对给定对象起作用并重新连接该对象
那么,有没有一种方法可以让@Audit
注释与session.saveOrUpdate()
一起工作,或者防止hibernate在映射过程中删除子项(这些子项在几分之一秒内是孤立的),而无需在映射之前更改列表的清除
我正在使用Hibernate 5.3.6.Final。清除和重新填充集合是个坏主意,正如您所发现的那样。您不能匹配子ID并根据需要添加/更新/删除。@实际上,我使用了一个映射框架(orika),我发现它如上所述工作,我无法更改它的用法以及它的工作方式。清除和重新填充集合是一个坏主意-正如您所发现的那样。您不能匹配子ID并根据需要添加/更新/删除。@事实上,我使用了一个映射框架(orika),我发现它如上所述工作,我无法更改它的用法以及它的工作方式。
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}]