简体   繁体   English

在Hibernate中从持久性上下文中分离实体中的实体

[英]Detach entity within entity from persistence context in Hibernate

Hibernate persists modified entities at the of transactional methods, I can avoid by using session#evict(entity). Hibernate会在事务方法中保留修改后的实体,我可以通过使用session#evict(entity)来避免。

If I detach it from the persistence context, the entities whithin it will also be detached? 如果我将其与持久性上下文分离,那么其中的实体也将被分离?

For instance, I have this classes: 例如,我有以下课程:

@Entity
public class User extends BaseEntity{
      @Column(name = "email")
      private String email;

      @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
      private List<Address> addresses;

      // getters and setters
}

@Entity
public class Address extends BaseEntity{
      @Column(name = "email")
      private String email;

      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = "USER_ID")
      private User user;     

      // getters and setters
}

If I detach a user object, but change the address object in it, will the address be persisted at the end of transaction? 如果我分离了一个用户对象,但更改了其中的地址对象,该地址在交易结束时是否会保留? Like this: 像这样:

User user = userDAO.getById(id);
session.evict(user);
Address address = user.getAddresses().get(0);
address.setNumber(number);
addressDAO.saveOrUpdate(address); //will this work?

Entities that are updated or deleted using a EntityManager.createQuery() are not loaded into the Persistence Context, this only happens for select queries, and when you use find() or merge() . 使用EntityManager.createQuery()更新或删除的实体不会加载到持久性上下文中,这仅适用于选择查询以及使用find()merge()

After you do an update or delete query your persistence context may actually be out-of-sync with the database, because the query doesn't update the entities which has already been loaded into the persistence context (you need to call refresh() to see the changes). 在执行更新或删除查询之后,您的持久性上下文实际上可能与数据库不同步,因为查询不会更新已经加载到持久性上下文中的实体(您需要调用refresh()来查看更改)。

If you load a number of user (into the persistence context), and later do Update User set status='active' where id IN (:ids) , then you have not modified any of the users in the persistence context, you have only modified the database. 如果您将多个用户(加载到持久性上下文中),然后在Update User set status='active' where id IN (:ids) ,则您尚未在持久性上下文中修改任何用户。修改了数据库。 To modify a user, you must modify the actually managed Entity by calling `aUser.setStatus('active'), when the transaction commits, JPA will check all managed entities against a copy created when it was loaded, and if anything has changed it will do an Update. 要修改用户,您必须通过调用`aUser.setStatus('active')来修改实际的受管实体,当事务提交时,JPA将对照加载时创建的副本检查所有受管实体,如果有任何更改,将进行更新。

If you are loading 5000 objects into the Persistence it may take some time for JPA to run though the entity graph, and detect the changes when the transaction commits. 如果要将5000个对象加载到Persistence中,则JPA可能需要一些时间才能通过实体图运行,并在事务提交时检测到更改。 If you didn't modify anything, and would like to speed up the change-detection, there are two ways to do this. 如果您未进行任何修改,并且想加快更改检测的速度,则有两种方法可以执行此操作。 Load your entities using a read-only query, this tells JPA that it does not need to keep a copy of the loaded entity. 使用只读查询加载您的实体,这告诉JPA它不需要保留已加载实体的副本。 The other option is to call EntityManager.clear() to throw away all managed entities. 另一个选择是调用EntityManager.clear()丢弃所有托管实体。 However, if you are interested in performance, the best solution is probably to avoid loading the entities into the persistence context. 但是,如果您对性能感兴趣,最好的解决方案可能是避免将实体加载到持久性上下文中。 As I understand you problem, you need to do a Update User set ... where id IN (:ids) and for that you only need the user's id so you don't need to load the user, you just need the ids, and therefore you can do List<Long> ids = em.createQuery("select u.id from User u where ...", Long.class).getResultList(); 据我了解,您需要做一个Update User set ... where id IN (:ids) ,为此,您只需要用户的ID,因此您无需加载用户,只需要ID,因此,您可以执行List<Long> ids = em.createQuery("select u.id from User u where ...", Long.class).getResultList();

Hope this clarifies things for you :) 希望这可以为您澄清事情:)

EDIT: this is written from a JPA perspective, but for hibernate EntityManager just forwards directly to SessionImpl , so the behavior is exactly as described, except for find() being called get() in native Hibernate. 编辑:这是从JPA角度编写的,但是对于休眠EntityManager只是直接转发给SessionImpl ,因此行为与所描述的完全相同,除了在本地Hibernate中将find()称为get()

Since JPA 2.0 从JPA 2.0开始

given an EntityManager you can call detach with the entity you want to be detached as parameter 给定一个EntityManager,您可以使用要分离的实体作为参数调用detach

void detach(Object entity)

more here 这里更多

if you use injection then you can inject an EntityManger in the service where you want to detach the required entity. 如果使用注入,则可以在要分离所需实体的服务中注入EntityManger。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM