Hibernate: best practice to pull all lazy collecti

2019-01-12 17:39发布

What I have:

@Entity
public class MyEntity {
  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
  @JoinColumn(name = "myentiy_id")
  private List<Address> addreses;

  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
  @JoinColumn(name = "myentiy_id")
  private List<Person> persons;

  //....
}

public void handle() {

   Session session = createNewSession();
   MyEntity entity = (MyEntity) session.get(MyEntity.class, entityId);
   proceed(session); // FLUSH, COMMIT, CLOSE session!

   Utils.objectToJson(entity); //TROUBLES, because it can't convert to json lazy collections
}

What a problem:

The problem is that I can't pull lazy collection after session has been closed. But I also can't not close a session in proceed method.

What a solution (coarse solution):

a) Before session is closed, force hibernate to pull lazy collections

entity.getAddresses().size();
entity.getPersons().size();

....

b) Maybe more ellegant way is to use @Fetch(FetchMode.SUBSELECT) annotation

Question:

What is a best practice/common way/more ellegant way to do it? Means convert my object to JSON.

9条回答
你好瞎i
2楼-- · 2019-01-12 18:08

With Hibernate 4.1.6 a new feature is introduced to handle those lazy association problems. When you enable hibernate.enable_lazy_load_no_trans property in hibernate.properties or in hibernate.cfg.xml, you will have no LazyInitializationException any more.

For More refer : https://stackoverflow.com/a/11913404/286588

查看更多
够拽才男人
3楼-- · 2019-01-12 18:10

It's probably not anywhere approaching a best practice, but I usually call a SIZE on the collection to load the children in the same transaction, like you have suggested. It's clean, immune to any changes in the structure of the child elements, and yields SQL with low overhead.

查看更多
Summer. ? 凉城
4楼-- · 2019-01-12 18:12

if you using jpa repository, set properties.put("hibernate.enable_lazy_load_no_trans",true); to jpaPropertymap

查看更多
够拽才男人
5楼-- · 2019-01-12 18:15

Not the best solution, but here is what I got:

1) Annotate getter you want to initialize with this annotation:

@Retention(RetentionPolicy.RUNTIME)
public @interface Lazy {

}

2) Use this method (can be put in a generic class, or you can change T with Object class) on a object after you read it from database:

    public <T> void forceLoadLazyCollections(T entity) {

    Session session = getSession().openSession();
    Transaction tx = null;
    try {

        tx = session.beginTransaction();
        session.refresh(entity);
        if (entity == null) {
            throw new RuntimeException("Entity is null!");
        }
        for (Method m : entityClass.getMethods()) {

            Lazy annotation = m.getAnnotation(Lazy.class);
            if (annotation != null) {
                m.setAccessible(true);
                logger.debug(" method.invoke(obj, arg1, arg2,...); {} field", m.getName());
                try {
                    Hibernate.initialize(m.invoke(entity));
                }
                catch (Exception e) {
                    logger.warn("initialization exception", e);
                }
            }
        }

    }
    finally {
        session.close();
    }
}
查看更多
手持菜刀,她持情操
6楼-- · 2019-01-12 18:15

Try use Gson library to convert objects to Json

Example with servlets :

  List<Party> parties = bean.getPartiesByIncidentId(incidentId);
        String json = "";
        try {
            json = new Gson().toJson(parties);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write(json);
查看更多
孤傲高冷的网名
7楼-- · 2019-01-12 18:16

Place the Utils.objectToJson(entity); call before session closing.

Or you can try to set fetch mode and play with code like this

Session s = ...
DetachedCriteria dc = DetachedCriteria.forClass(MyEntity.class).add(Expression.idEq(id));
dc.setFetchMode("innerTable", FetchMode.EAGER);
Criteria c = dc.getExecutableCriteria(s);
MyEntity a = (MyEntity)c.uniqueResult();
查看更多
登录 后发表回答