4
votes

Context : Development of in-house web applications using play framework (1.3), hibernate (4.3.8) and some Groovy on the html side.

I'm currently working with Hibernate and I was assigned to find some optimization techniques. We have some loading issue because everything is fetched lazily and when we try to access it with Groovy, Hibernate will rain down tons of requests that takes a huge amount of time making our applications really slow.

So I'm trying to tweak our find method to fetch everything that I need so that Hibernate don't have to.

Here's my class :


    @Entity
    @Table(name="business_partner", schema = "public")
    public class BusinessPartner extends Model{
        @Id
        @Column(name="business_partner_id", updatable=false, nullable=false)
        @GeneratedValue(strategy=GenerationType.TABLE, generator="businessPartnerGenerator")
        @TableGenerator(name="businessPartnerGenerator",
                table="key_generator",
                pkColumnName="table_name",
                valueColumnName="next_id",
                allocationSize=1)
        private Integer businessPartnerId;

        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "airline_id")
        @Unique
        private Airline airline;

        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "trader_country_id")
        private Country traderCountry;

        @Column(name = "name", nullable = false)
        @Required
        @MaxSize(50)
        @Unique
        private String name;

        @Column(name = "code", updatable = false)
        @MaxSize(5)
        @Unique
        private String code;

        @Column(name = "is_active", nullable = false)
        private Boolean isActive;

        @OneToMany(fetch = FetchType.LAZY, mappedBy="businessPartner", cascade=CascadeType.ALL)
        @Fetch(FetchMode.SUBSELECT)
        private List lstBusinessPartnerTypes = new ArrayList();

        @OneToMany(fetch = FetchType.LAZY, mappedBy="businessPartner", cascade=CascadeType.ALL)
        @Fetch(FetchMode.SUBSELECT)
        private List lstBusinessPartnerAddresses = new ArrayList();

Here's my criteria :


public static List findAll(){
        Session oSession = SessionManager.createSession();

        List lstBusinessPartners = (List)oSession.createCriteria(BusinessPartner.class)
                .createAlias("lstBusinessPartnerAddresses", "lstBPA")
                .createAlias("lstBusinessPartnerTypes", "lstBPT")
                .setFetchMode("airline", FetchMode.JOIN)
                .setFetchMode("lstBPA.country", FetchMode.SELECT)
                .setFetchMode("lstBPT.typeBusinessPartner", FetchMode.SELECT)
                .addOrder(Order.asc("code"))
                .list();

        SessionManager.closeSession(oSession);

        return lstBusinessPartners;
    }

So I need to access airline and a child of each one to many lists.

I can access airline, there is no problem there. It's when I try to access an object in the list that it gets tricky. I can't load the lists nor their child (as you can see from my criteria I'm trying to access country in one list and type business partner in the other). I get this kind of request for every business partner :

Hibernate example

So my question is this : Is it possible to fetch a lazy list using criteria ? And if so how ?

2

2 Answers

2
votes

So I found my answer if anyone stumbles on this post looking for an answer. You need to create an alias for your list and specify the JoinType as following :

BusinessPartner oBusinessPartner = (BusinessPartner)oSession.createCriteria(BusinessPartner.class, "BP")
            .add(Restrictions.eq("businessPartnerId", iBusinessPartnerId))
            .createAlias("lstBusinessPartnerTypes", "lstBPT", JoinType.LEFT_OUTER_JOIN)
            .createAlias("lstBPT.typeBusinessPartner", "TBP", JoinType.LEFT_OUTER_JOIN)
            .createAlias("lstBPT.accountGroup", "AG", JoinType.LEFT_OUTER_JOIN)
            .createAlias("AG.typeBusinessPartner", "AGTBP", JoinType.LEFT_OUTER_JOIN)
            .createAlias("lstBusinessPartnerAddresses", "lstBPA", JoinType.LEFT_OUTER_JOIN)
            .createAlias("lstBPA.country", "BPAC", JoinType.LEFT_OUTER_JOIN)
            .createAlias("lstBPA.language", "BPAL", JoinType.LEFT_OUTER_JOIN)       

            .uniqueResult();
1
votes

You could initialize each collection with Hibernate.initialize(Object) method. So in your DAO layer, it's only necessary to retrieve the 'father' object and then call this method for each child.