ibatis-user-java mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Kai Grabfelder <nos...@kinokai.de>
Subject Re: Laziness, downcasting and <discriminator,id> associations
Date Mon, 01 Dec 2008 22:01:42 GMT
@Carlos: yes I'm pretty much using a dedicated set of statement per usecase. Of course I'm
reusing as much as
I can, e.g. using the generic ibator generated example classes and my result mappings. But
Rick summarized my
points to a pretty good extend I think.

@Rick: thanks to your post I don't need to post my opinions as they are pretty much the same
;-)

Regards

Kai

--- Original Nachricht ---
Absender: Rick
Datum: 01.12.2008 22:45
> I also noticed that you mentioned a "web application."  As a web app, I
> doubt you really need 'lazy loading' and my guess is you'd be just fine
> without it.
> 
> On Mon, Dec 1, 2008 at 4:42 PM, Rick <rickcr@gmail.com> wrote:
> 
>> I haven't read the entire post, but when I saw all your comments on "lazy,"
>> I started to wonder what you are needing it for.
>>
>> I'm not an expert in iBATIS by any stretch but I typically find I don't
>> need the lazy features and I have some pretty complex relationships.  (Side
>> note, I'm also coverting an existing Hibernate application to iBATIS.)
>>
>> If I need all the data up front, yes, I will create one query to get it all
>> and iBATIS handles it just fine. You mentioned a huge cartesian result set -
>> if that were the case, I wouldn't think you would need it all up front in
>> which case I still don't rely on the lazy approach.
>>
>> A DAO method is so small and simple, why not just call a dao with what you
>> need if there is some sort of drill down? I guess I'd have to see more of
>> your exact user experience of what you are doing since that does make a
>> difference. Can you explain more what you are doing with your collection
>> that you return? Are you going over every element and then calling a
>> property which triggers the lazy load?  If that were the case, I don't think
>> a lazy solution is good either, since lazy only makes sense (imo) if you
>> aren't sure you need all the data (and even then I don't get what the big
>> deal is.)
>>
>> In my case, my dao methods are vey lightweight...
>>
>> public NPPSystem findBySystemName(String nppSystemName) {
>>         return (NPPSystem)
>> getSqlMapClientTemplate().queryForObject("NPPSystem.find", nppSystemName );
>>     }
>>
>> If I wanted I could always just call that dao to get what I need.
>> In other words, doing ..
>>
>> Foo foo = ContainingObject.getFoo();   //lazy load Foo
>>
>> isn't much less typing than
>>
>> Foo foo = fooDao.findFoo(ContaingObject.getFooID()); //get Foo from DAO
>> call
>>
>> So I never really found a need to rely on "lazy" features. (Typically the
>> business requirements don't work that way either. For example you typically
>> need "everything" populated or your UI goes through some step where you want
>> to drill down more at which point I just call my service/dao and get what I
>> need.
>>
>> I rambled on fast so sorry if I didn't make much sense. I can clarify more
>> if you like.
>>
>>
>>
>> On Mon, Dec 1, 2008 at 12:22 PM, Carlos Pita <carlosjosepita@gmail.com>wrote:
>>
>>>
>>>
>>>> I have to admit that I never used the lazy features of iBATIS. Lazyness
>>>> by Default was one of the reasons why
>>>> I moved over from hibernate to iBATIS. And I know a bunch of other devs
>>>> that are not and will not use lazy
>>>> loading. Imho it does not make sense for web applications or restful
>>>> service interfaces and introduces a lot
>>>> of problems (open session in view, serialization of result sets,
>>>> performance etc.).
>>>
>>>
>>> Could you please develop your position a bit more? I'm interested in any
>>> approach that gets rid of any amount of magic that works behind the scenes.
>>> If avoiding all laziness happens to be a workable approach, I'll be all for
>>> it.
>>>
>>> For example, to trigger the discussion:
>>>
>>> Do you work out a query per use case that eager fetches (by means of joins
>>> and/or immediate subselects) the exact graph needed for that use case?
>>>
>>> There are obvious problems with join fetches for entities that have more
>>> than one 1-N relationships because of the potentially huge cartesian product
>>> that they generate; I can figure out more or less laboriuos solutions to
>>> them using ibatis to fetch and map one or more of the associated collections
>>> by separate queries and then merging the results. And anyway lazy fetching
>>> would avoid the cartesian product to incur in the even worse n+1 problem.
>>> How do you approach this kind of situation?
>>>
>>> Then, there are bidirectional associations, which I currently implement
>>> keeping a memory cache with weak references to get the N-1 side
>>> (child.getParent() should be a cache hit). Eagerness would imply an extra
>>> query here, for a parent that more often than not has been already fetched.
>>>
>>> That are some of the many issues that came to my mind.
>>>
>>> > Nevertheless: feel free to create a jira issue with your proposed
>>> patches. And it would be great if you could
>>> > link to all the other lazy issues that are related. Maybe we should
>>> start a vote about the direction of lazy
>>> > loading with iBATIS in the future...
>>>
>>> Sure.
>>>
>>>
>>> Best regards
>>> -Carlos
>>>
>>>
>>>>
>>>>
>>>> I'm not sure what the plans are for iBATIS 3.0. I've seen quite different
>>>> opinions regarding lazyness on the
>>>> whiteboard (
>>>> http://opensource.atlassian.com/confluence/oss/display/IBATIS/iBATIS+3.0+Whiteboard)
>>>> but I don't
>>>> know the status. @Clinton: any news about that?
>>>>
>>>>
>>>>
>>>>
>>>> Regards
>>>>
>>>> Kai
>>>>
>>>>
>>>> --- Original Nachricht ---
>>>> Absender: Carlos Pita
>>>> Datum: 01.12.2008 16:51
>>>> > Hi,
>>>> >
>>>> > I'm evaluating the possibility to migrate a web application that is
>>>> already
>>>> > in production from hibernate to ibatis. As a part of this I'm
>>>> implementing
>>>> > skeletal versions of our most complex mappings, as a proof of concept.
>>>> The
>>>> > application contains some overlapping hierarchies rooted at interfaces
>>>> that
>>>> > are certainly hard to map into hibernate entities. For example, many
>>>> > different things can be commentable, rateable, abusable (meaning that
>>>> abuses
>>>> > can be reported on them), etc. These concepts are naturally modelled
as
>>>> > interfaces. Bidirectional associations exist between, say, commentables
>>>> and
>>>> > comments:
>>>> >
>>>> > commentable <-----------*> comment
>>>> >
>>>> > Following the example, a product and a user profile are commentables:
>>>> >
>>>> >     commentable <---------*> comment
>>>> >          ^   ^
>>>> >         |   |
>>>> >     product  profile
>>>> >
>>>> > Of course, both product and profile belong to different class
>>>> hierarchies
>>>> > besides being commentable. The link from comment to commentable could
>>>> be
>>>> > implemented as pointing to an union select of product and profile, or
>>>> using
>>>> > a target table discriminator column as in:
>>>> >
>>>> > comment {
>>>> >   text
>>>> >    commentable_kind : { product, profile }
>>>> >   commentable_id
>>>> > }
>>>> >
>>>> > I've found at least two ways to satisfactorily map the above using
>>>> ibatis,
>>>> > which encourages me to continue my evaluation and eventually get into
>>>> the
>>>> > (considerable) work of migrating the entire app to ibatis.
>>>> >
>>>> > But then I've to say that I bumped my head against issue #1 here
>>>> >
>>>> >
>>>> http://opensource.atlassian.com/confluence/oss/display/IBATIS/Lazy+loading+issues
>>>> >
>>>> > That happened when I expected to get the commentable product out of
a
>>>> > comment: (Product)(comment.getCommentable()).
>>>> >
>>>> > Nevertheless, I found out the following patch
>>>> >
>>>> > https://issues.apache.org/jira/browse/IBATIS-463
>>>> >
>>>> > which is fine but only a kludge for the very specific situation. Why
>>>> not
>>>> > allow laziness to be specified on a per subselect basis (of course,
>>>> taking
>>>> > into account the default app-wide setting also)? Required changes to
>>>> the
>>>> > source are minimal (the ResultMapping could be passed to loadResult
in
>>>> order
>>>> > it to check for the lazy attribute), and that solves the lazy downcast
>>>> > problem but also provides a finer control over laziness/eagerness of
>>>> the
>>>> > association. The logic to enable laziness would then be:
>>>> > global-laziness-enabled && local-laziness-enabled -> enable
laziness
>>>> for
>>>> > this subselect.
>>>> >
>>>> > That said, for associations specified by a pair <discriminator,id>
as
>>>> above,
>>>> > the discriminator is available *before* fetching the associated entity.
>>>> One
>>>> > way of mapping the aforementioned association is:
>>>> >
>>>> > <resultMap id="commentMap" class="comment">
>>>> >     ....
>>>> >    <discriminator column="commentable_kind" javaType="int">
>>>> >         <subMap value="1" resultMap="productCommentableMap"/>
>>>> >        <subMap value="2" resultMap="profileCommentableMap"/>
>>>> >     </discriminator>
>>>> > </resultMap>
>>>> >
>>>> > <resultMap id="productCommentMap" class="comment" extends="commentMap">
>>>> >      ....
>>>> >     <result property="commentable" column="commentable_id"
>>>> > select="selectProductById" />
>>>> > </resultMap>
>>>> >
>>>> > <resultMap id="profileCommentMap" class="comment" extends="commentMap">
>>>> >      ....
>>>> >     <result property="commentable" column="commentable_id"
>>>> > select="selectProfileById" />
>>>> > </resultMap>
>>>> >
>>>> > Obviously selectProductById would be mapped by a productMap which
>>>> builds a
>>>> > product and selectProfileById by a profileMap which builds a profile:
>>>> >
>>>> > <select id="selectProductById" resultMap="productMap" (or
>>>> > resultClass="product")>
>>>> >     ....
>>>> > </select>
>>>> >
>>>> > <select id="selectProfileById" resultMap="profileMap" (or
>>>> > resultClass="profile")>
>>>> >     ....
>>>> > </select>
>>>> >
>>>> > But despite the concrete class info is available, as far as the
>>>> association
>>>> > is lazy ibatis will generate a commentable proxy, not a product or
>>>> profile
>>>> > one.
>>>> >
>>>> > I think it would be an improvement if instead of just considering the
>>>> class
>>>> > in the bean signature ibatis also took into account the class of the
>>>> > resultmap involved, and favoured the "more concrete" one, because
>>>> sometimes
>>>> > the mapping containes more precise information about the specific use
>>>> case
>>>> > than the general interface. In this case, product and profile would
be
>>>> > picked instead of just commentable. This way, we have a lazy and
>>>> > downcasteable polymorphic association (for this kind of mapping).
>>>> >
>>>> > Briefly, I'm proposing two minor changes for the java version:
>>>> >
>>>> > 1) add a lazy attribute to the result tag that takes effect only when
>>>> the
>>>> > select attribute is also given. This attribute won't activate laziness
>>>> if
>>>> > it's globally disabled, but will deactivate it when it's globally
>>>> enabled.
>>>> >
>>>> > 2) when creating a 1:1 proxy prefer the more concrete class between
the
>>>> one
>>>> > given in the property signature and the one given in the resultMap for
>>>> the
>>>> > "delayed" query.
>>>> >
>>>> > I'm going to implement these changes anyway, because I need them. But
I
>>>> > really would like to know what do you think about the ideas and whether
>>>> > you're also interested in patching the 2.x trunk or not.
>>>> >
>>>> > Before I mentioned that I found out two ways of mapping the
>>>> > <discriminator,id> association. The second one involves using
a dynamic
>>>> > select instead of two submaps. This select (say
>>>> > selectCommentableFromKindAndId) chooses the target table (product or
>>>> > profile) according to the discriminator (kind) value. But I realized
>>>> that
>>>> > the resultMap for a dynamic select is itself static, somehow
>>>> diminishing the
>>>> > flexibility that dynamic tags introduce. Of course, the resultMap for
>>>> the
>>>> > select could contain a discriminator to alleviate the problem. But I
>>>> think
>>>> > that the resultMap is so closely related to the query that the
>>>> possibility
>>>> > to modify the second (by means of dynamic tags) should be accompanied
>>>> by the
>>>> > possibility to modify the first based on dynamic criteria. What do you
>>>> > think?
>>>> >
>>>> > Best regards
>>>> > -Carlos
>>>> >
>>>>
>>>>
>>>
>>
>>
>> --
>> Rick
>>
> 
> 
> 


Mime
View raw message