0

Imagine this relationshipt where a stock has many to many with category.

Stock

@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinTable(name = "stock_category" , joinColumns = { 
        @JoinColumn(name = "STOCK_ID", nullable = false, updatable = false) }, 
        inverseJoinColumns = { @JoinColumn(name = "CATEGORY_ID", 
                nullable = false, updatable = false) })
public Set<Category> getCategories() {
    return this.categories;
}

Category

 @ManyToMany(fetch = FetchType.LAZY, mappedBy = "categories")
public List<Stock> getStocks() {
    return this.stocks;
}

When I tried to list all categories and your stocks I was getting Lazy Load exception - no session or session was closed.

So I changed my method to initialize all stocks from every category. If I want to initialize another entity I just put it inside for loop:

 session = HibernateUtil.getSessionFactory().openSession();
            Criteria cri = session.createCriteria(Category.class)
                     .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

            List<Category> categories = (List<Category>) cri.list();

            for (Category c :categories) {
                Hibernate.initialize(c.getStocks()); 
            } 

But I get an SQL for every Category to initialize stocks and I'm thinking this is not good.

So, I tried to use .setFetchMode("stocks", FetchMode.JOIN) and I'll be getting one SQL but if I want use fecthmode and need to join with another entity i'll getting "cannot simultaneously fetch multiple bags".

Product

@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinTable(name = "product_category" , joinColumns = { 
        @JoinColumn(name = "PRODUCT_ID", nullable = false, updatable = false) }, 
        inverseJoinColumns = { @JoinColumn(name = "CATEGORY_ID", 
                nullable = false, updatable = false) })
public Set<Category> getCategories() {
    return this.categories;
}

List:

session = HibernateUtil.getSessionFactory().openSession();
            Criteria cri = session.createCriteria(Category.class)
                     .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
                     .setFetchMode("stocks", FetchMode.JOIN)
                     .setFetchMode("products", FetchMode.JOIN);

I'm not convinced about which is the best way to do this using hibernate. I read a lot about OpenSessionInView but some suggest that is a bad pattern.

gustavomr
  • 69
  • 2
  • 16
  • `but if I want use fecthmode and need to join with another entity`, what do you mean by this, can you add some code and also complete stacktrace of the error so that it is clear to understand – Chaitanya Aug 26 '14 at 17:49
  • @user2065083 I mean that if I want do list all categories and categories has tow entites related (stock and product) this error happens! Changed this code to show it. – gustavomr Aug 26 '14 at 19:57

1 Answers1

2

So I understand that your Category entity is having ManyToMany relationship with entities Stock and also Product. In your Category entity, if you try to use List for properties stocks amd products and then if you want to set the fetch mode to JOIN as :

`criteria.setFetchMode("stocks", FetchMode.JOIN).setFetchMode("products", FetchMode.JOIN);`

then Hibernate throws an exception as:

 org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags

To fix this issue you have to change the type of properties for stocks & products to Set instead of List in your Category entity class.

Chaitanya
  • 15,403
  • 35
  • 96
  • 137
  • I modify this and worked. But Which one is the best way to do this? Using Hibernate.initialize or setFetchMode ? is there any other way? – gustavomr Aug 26 '14 at 20:24
  • 1
    `setFetchMode` is better compared to `Hibernate.initialize`, because Hibernate issues less number of queries using `setFetchMode`. You can verify that by looking at the queries generated by Hibernate. – Chaitanya Aug 26 '14 at 21:31
  • I´m trying to understand pros and cons about solutions. Using setFetchMode bring only the desired data but would be necessary one query for each accessed collection/lazy entity. How it could be made using JPA (because setFetchMode e Hibernate.initialize are hibernate eclusive implementations) ? – gustavomr Aug 26 '14 at 23:03
  • that is a different question and specific to `JPA`, so better ask in a separate post to get correct answers. Also you can refer to this post for more details --> http://stackoverflow.com/questions/4388486/fetchmode-in-jpa-2-criteriaquery – Chaitanya Aug 27 '14 at 05:39