休眠合并与持久化。有变化吗?

时间:2020-01-26 22:50:36

标签: java hibernate jpa orm

我有一个具有以下代码的应用程序,在升级休眠(从5.3.2到5.4.10)之前一切正常。

    List<UserRole> roles = entity.getRoles();
    for(UserRole r : roles) {
        Em.get().remove(r);
    }
    roles.clear();

    for(RoleEnum r : selectedRoles) {
        UserRole role = new UserRole(entity, r);
        Em.get().persist(role);
    }

    Em.get().merge(entity);
    Em.get().flush();

所以,然后我开始出现异常

由于:org.hibernate.TransientPropertyValueException:对象 引用未保存的瞬时实例-保存瞬时实例 刷新之前:WEBPIECESxPACKAGE.base.libs.UserRole.user-> WEBPIECESxPACKAGE.base.libs.UserDbo

当我“添加”新的用户实体时会发生这种情况。如果我编辑一个旧用户(它使用相同的确切代码),那就没问题了。

我改为Em.get()。persist(entity),它可以为DB添加新实体并编辑旧实体。

但是文档仍然说旧的JPA /休眠用于持久化的是

@如果实体已经存在,则抛出EntityExistsException。

每个人都在使用持久性作为添加或编辑功能吗? (即,有一个函数可以保存或编辑,因为我不太在意,这非常好,而且休眠状态可以从现有的数据库ID得知是添加还是编辑,因此没有理由不添加或编辑)一次调用)。

我现在正在使用em.persist(),它正在用于UPDATE或SAVE ...奇怪

可以在第110行看到 https://github.com/deanhiller/webpieces/blob/master/webserver/webpiecesServerBuilder/templateProject/WEBPIECESxAPPNAME/src/main/java/webpiecesxxxxxpackage/web/crud/CrudUserController.java

我正在使用Hibernate 5.4.10

谢谢, 院长

1 个答案:

答案 0 :(得分:1)

Update Vs Merge的可能重复项

这里发生的是: 编辑模式:

List<UserRole> roles = entity.getRoles(); //Gets Existing Roles from DB
for(UserRole r : roles) {
    Em.get().remove(r); //Removes Roles to existing user
}
roles.clear(); // Clean up local memory

for(RoleEnum r : selectedRoles) { // User Input Roles
    UserRole role = new UserRole(entity, r); // New Entity with existing user
    Em.get().persist(role); // Role Entity Referenced to existing user object, saved
}

Em.get().merge(entity); // ?? No Need in edit unless roles are stored in user table
Em.get().flush();

新用户模式:

List<UserRole> roles = entity.getRoles(); // New Detached User Entity Roles
    for(UserRole r : roles) { // Probably Empty Roles Array
        Em.get().remove(r); // Removed roles
    }
    roles.clear(); // Clean up Memory

    for(RoleEnum r : selectedRoles) { // Copy from App Roles
        UserRole role = new UserRole(entity, r); //Create new role
        Em.get().persist(role); //Save Role to DB
    }

    Em.get().merge(entity); // Trying to merge non existing Entity <-- This is where error appears
    Em.get().flush();

persist方法之所以起作用,是因为它决定了何时使用插入或更新命令。由于新用户实体未设置ID,因此它不知道如何处理,尽管它过去可能有用,但在此线程merging a detached or new entity with an existing entity in hibernate/jpa best practice question

中很好地解释了Mergig的实际行为。

亲自看看:

如果您的实体是独立实体,那么您真正需要做的唯一一件事 是调用entityManager.merge(user)。您不需要执行任何 查找器方法。如果您的实体不是独立的,而是新的(它确实 未指定ID),您应该在 数据库上对该实体执行任何修改操作之前 然后将其合并。

此处提供了另一个详细参考: persist() and merge() in JPA and Hibernate

这是docs的参考:

可序列化 save(Object object)抛出HibernateException

 Persist the given transient instance, first assigning a generated identifier. (Or using the current value of the identifier property if the assigned generator is used.) This operation cascades to associated instances if the association is mapped with cascade="save-update". 
 Parameters:
     object - a transient instance of a persistent class 
 Returns:
     the generated identifier 
 Throws:
     HibernateException

坚持

voidpersist(字符串entityName, 对象对象) 抛出HibernateException

Make a transient instance persistent. This operation cascades to associated instances if the association is mapped with cascade="persist".

The semantics of this method are defined by JSR-220.

Parameters:
    object - a transient instance to be made persistent 
Throws:
    HibernateException

合并

对象合并(字符串entityName, 对象对象) 抛出HibernateException

Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session. This operation cascades to associated instances if the association is mapped with cascade="merge".

The semantics of this method are defined by JSR-220.

Parameters:
    object - a detached instance with state to be copied 
Returns:
    an updated persistent instance 
Throws:
    HibernateException

save()和persist()导致SQL INSERT,在SQL中删除() 在SQL UPDATE中进行DELETE和update()或merge()。更改为永久 刷新时间检测到实例,并且还会导致SQL UPDATE。 saveOrUpdate()和copy()会导致INSERT或 更新。

结论:功能按预期运行。