Manually created object in DAO for insert is not bound with mybatis, hence we can not call relationship methods on it if lazy loading is enabled.

84 views
Skip to first unread message

Parag Dhikale

unread,
May 14, 2013, 11:31:19 AM5/14/13
to mybati...@googlegroups.com
Hi,

I am using mybatis 3.2.2.

In my application, to insert new row in the table, I have 'create' method in DAO class of the object(POJO) which is for that table.
In that method I create POJO object using 'new' and set its properties using setters with values got in create method parameters.
Then I pass that object(pojo) to the mapper interface's 'create' method which is mapped to the 'insert' statement in mapper xml.
That insert statement ultimately uses property names from this POJO and inserts into table.

The business logic code requires that dao.create(***)  should return the created pojo. So I am returning the same pojo which I created using 'new' back to the caller.

Now problem is, when caller tries to call relationship method on that object, it doesn't execute lazy loaded association query, hence it returns null and my application fails.

Let me try to explain this with example:

Table : EMP

POJO: EmpPojo.java

Mapper interface: EmpMapper.java

Mapper Xml : EmpMapper.xml

Dao : EmpDao.java

Create method of EmpDao:

public EmpPojo create(BigDecimal empNo, String empName){

    EmpPojo emp = new EmpPojo();

    SqlSession session = null;

    try{

        session = sqlSessionFactory.openSession();

        EmpMapper empMapper = session.getMapper(EmpMapper.class);

        emp.setEmpNo(empNo);
        emp.setEmpName(empName);

        empMapper.create(emp);

    }  catch (PersistenceException pex) {
        } catch (Exception ex) {
        } finally {
            closeSession(session);
        }
    return emp;
}

EmpPojo:
pubic class EmpPojo{
    BigDecimal empNo;
    String empName;

    //Relationship field
    EmailPojo email;
}

(NOTE: please ignore if some things are missing, its just to give you clear idea, I am just mentioning what is needed to understand the problem)

TestEmp.java:

EmpPojo newEmp = (new EmpDao()).create(1,"Rock");

newEmp.getEmail();


This returned pojo newEmp is not bound to the mybatis mapper, it is treated as a normal object.
Hence when I call 'newEmp.getEmail()' it doesn't call association query for 'email' and hence it returns null.

To overcome this problem, for now, I am calling 'findByPrimaryKey(primarykey)' after each call of create to get the same object but which is bound with mybatis, and hence relationship method calls on this pojo returned from find*** method calls association queries and returns relationship object properly.

But this workaround is affecting my performance.

Does mybatis has any sort of settings or something through which I can directly get object bound with mybatis in single call of create?

Thanks,
Parag




Parag Dhikale

unread,
May 14, 2013, 11:32:20 AM5/14/13
to mybati...@googlegroups.com
My mybatis config settings are as follows:

    <settings>
        <setting name="aggressiveLazyLoading" value="false" />
        <setting name="lazyLoadingEnabled" value="true" />
        <setting name="jdbcTypeForNull" value="VARCHAR" />
        <setting name="defaultExecutorType" value="REUSE"/>
        <setting name="defaultStatementTimeout" value="25000"/>
        <setting name="lazyLoadTriggerMethods" value="clone"/>
        <setting name="logImpl" value="LOG4J"/>
    </settings>

Jeff Butler

unread,
May 14, 2013, 12:30:48 PM5/14/13
to mybati...@googlegroups.com
Why not fill out the associations after you do the create and then return the complete object your client code expects?

If you are so committed to lazy loading that you must have it in all cases, then your workaround is the only thing I can think of.

Jeff Butler


--
You received this message because you are subscribed to the Google Groups "mybatis-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mybatis-user...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Parag Dhikale

unread,
May 15, 2013, 2:20:59 AM5/15/13
to mybati...@googlegroups.com
It is not possible in our application to fill out associations after create before returning object, as there are so many associations and are used at many places.

Is there no other way in mybatis by which we can just bind this object with mybatis mapper?

Jeff Butler

unread,
May 15, 2013, 9:58:27 AM5/15/13
to mybati...@googlegroups.com
If you fill out the associations with lazy loaded objects, you should (hopefully) end up with nearly the same performance.

<myOpinionOnly>
I've been wondering if you have an application that has a very rich and complex object model.  It sounds like you do.  As you're finding, MyBatis is often not the best fit for persisting a complex object model directly.  As sad as it may sound to say this, MyBatis is much better at working with the so-called "anemic domain model".  But in my experience, anemic domain model is a far better fit for web applications anyway.

Most of the time in web applications you do not need the entire domain to be loaded up for a simple transaction - and loading the whole domain is costly and wasteful.  What if you have a page that is modifying some deeply nested object?  Even with lazy loading, you will have to load all the parent objects just to get to the nested object - and those parent objects may never be used in your transaction.

The rich domain model works incredibly well in situations where the model can be loaded and retained across transactions.  That's not the case in web applications.

If this is the situation you are in, I would urge you to consider adapting your object model to more closely match the architecture of the tools you use.  I believe you'll be much happier in the end if you will do this.
</myOpinionOnly>

Jeff Butler
Reply all
Reply to author
Forward
0 new messages