-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 
Author Message
 Post subject: Implementing a CompositeUserType that can do associations
PostPosted: Thu Feb 19, 2004 7:53 pm 
Pro
Pro

Joined: Tue Aug 26, 2003 8:07 pm
Posts: 229
Location: Brisbane, Australia
Apologies, if I have cross-posted this. I thought I posted it yesterday, but now I can't find it.
I think Firebird is playing games.

Anyway, I'm trying to reimplement the AuditInfo Custom Type pattern to be a bit more useful in our application.
http://www.hibernate.org/48.html

The problem is that even when the AuditInfo is a CompositeUserType, Hibernate doesn't know about the relationship between the createdBy column of the entity and the application's User table.

What this means is that when you actually want to display attributes of the creating user of an entity to the client, you can't query for them directly.
You either have to iterate across a collection calling load(User.class, entity.getAuditInfo().getCreatedBy()), or manually join the entity table and the user table and use some of Hibernates more esoteric projection features.

Both approaches are pretty unsatisfactory.
What I want to do is extend the AuditInfo/Interceptor pattern so that the createdBy/updatedBy attributes are modelled as associations to User objects (a normally mapped object in our application) instead of as Long objects.

The problem is that I can't see how to write the CompositeUserType.nullSafeGet() method that would need to construct the User objects.
The User class in our application is mapped as lazy, and I would definitely want the semantics of that to be obeyed by the UserType. I don't want to always be joining to the user table when it's not necessary, but similarly I would want to take advantage of the FETCH keyword when it is used.

Can anyone given me some tips on where to look in the doco?
Or are there maybe some examples? I looked in the "eg" and "test" directories but couldn't find anything that seemed relevant.
If there's no doco or examples, can anyone point me to the areas of the API I need for the following:
- figuring out whether the User object should be eagerly or lazily fetched
- recreating a normally mapped entity class (User) from within the nullSafeGet() method

The more I think about it, I don't understand how Hibernate will know how to construct the SQL query when a user is trying to read normal entities and eagerly fetch the audit-related User. I looked at the SessionImplementor interface, but that didn't seem to provide anything that would tell me whether I was eagerly or lazily loading the User objects.

Please let me know if what I am trying to do is not possible so I can figure out some other solution for getting the attributes of the audit-related users.

_________________
Cheers,
Shorn.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 20, 2004 3:48 am 
Pro
Pro

Joined: Tue Aug 26, 2003 8:07 pm
Posts: 229
Location: Brisbane, Australia
Ok, so I think I've managed to implement normal loading of this thing.
I've implemented nullSafeGet() to look like this:
Code:
    public Object nullSafeGet(
        ResultSet rs, String[] names, SessionImplementor session, Object owner )
    throws HibernateException, SQLException {
        GoodAuditInfo ai = new GoodAuditInfo();

        ai.setLastUpdated( (java.sql.Timestamp)
            Hibernate.TIMESTAMP.nullSafeGet(rs, names[0]) );
        ai.setCreated( (java.sql.Timestamp)
            Hibernate.TIMESTAMP.nullSafeGet(rs, names[1]) );
       
        ClassPersister userPersister =
            session.getFactory().getPersister(User.class);
       
        Long updateKey = (Long) Hibernate.LONG.nullSafeGet(rs, names[ 2 ]);
        Long createKey = (Long) Hibernate.LONG.nullSafeGet(rs, names[ 3 ]);

        ai.setUpdatedBy( (User) userPersister.createProxy(updateKey, session) );
        ai.setCreatedBy( (User) userPersister.createProxy(createKey, session) );

        return ai;
    }

Our User object is proxied, so this seems to work fine. The lazy initialization of the User objects works fine too, so that seems ok.

My only problem now is eager fetching.
If I use a criteria query and call criteria.setFetchMode("auditInfo.createdBy", FetchMode.EAGER), Hibernate just seems to ignore the fetchmode, but it still works fine.
If I use HQL like this session.find("from AuditEntity as _e left join fetch _e.auditInfo.createdBy"), then Hibernate seems to get confused and do a self-join of the AuditEntity class.

This is still heaps better, since we no longer have to call session.load(User.class, entity.getAuditInfo().getCreatedBy(), but it's still pretty inefficient when you want to get the user details for a bunch of entities that were all created by different users.

Any tips on how I can do eager fetching with this setup?

_________________
Cheers,
Shorn.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 20, 2004 4:01 am 
Pro
Pro

Joined: Tue Aug 26, 2003 8:07 pm
Posts: 229
Location: Brisbane, Australia
If I were to implement the auditInfo attribute of normal entities as a Component, rather than a UserType - would that mean I couldn't update the attributes of that component from an Interceptor (thus making it useless for the auditing pattern)?

It occurs to me now that this would be easy to do with a component (or am I mistaken?).

_________________
Cheers,
Shorn.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.