有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何将Hibernate与DtoMapping和@Audited一起使用

我已经审核了具有单向一域映射的父实体和子实体类。我有两个具有相同字段的DTO类(包括id)和一个从DTO映射到实体的映射器。 如果在DTO类id字段中设置了Mapper.map(ParentDto parentDto, Parent.class)方法将不会实例化父实体的新实例,而是根据其id从数据库加载实体,然后映射加载实体上的字段。映射childs{}时,方法也会尝试按其id从数据库加载子项

我的问题是,在映射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) 个答案