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.  [ 5 posts ] 
Author Message
 Post subject: Using Hibernate to generate primary keys on object creation
PostPosted: Wed Aug 24, 2005 4:23 am 
Newbie

Joined: Thu Nov 25, 2004 11:44 am
Posts: 15
Location: Woodbridge UK
I am experimenting with an alternative approach to primary key generation and would welcome any comments on it.

I have difficulties with the idea of having to have business key semantics in my equals() and hashCode() implementations for my persistent classes.
Not all of the tables have natural or obvious business keys. Some would use dates as business keys, and I don't want to have to worry about date synchronization to ensure object identity integrity. That's what the primary key is for.

In normal circumstances the identifier cannot be used because the persistent objects would not behave properly when added to sets.

One way around this is to mandate that primary key values are inserted manually when the object is first created (i.e. is transient), but before being added to a set.

Here's my approach to implementing this:
1) define the identifier element as before, as if I were assigning IDs the normal way
2) override Spring's LocalSessionFactoryBean. Here, I extract the identifiers during the Configuration postprocessing, and store them locally. I then substitute the identifier generation strategy with assigned, so that when the session factory is built, it is as if I had specified "assigned" for all of the generators

Here's the code:

Code:
public class HibernateSessionFactoryBean extends LocalSessionFactoryBean
{

    private Map<String, IdentifierGenerator> identifierGenerators = new HashMap<String, IdentifierGenerator>();

    @Override
    protected void postProcessConfiguration(Configuration config) throws HibernateException
    {
       
       
        Iterator classes = config.getClassMappings();
        Settings settings = config.buildSettings();

        while (classes.hasNext())
        {
            PersistentClass model = (PersistentClass) classes.next();
            if (!model.isInherited())
            {
               
                KeyValue identifier = model.getIdentifier();
               
                IdentifierGenerator generator = identifier.createIdentifierGenerator(settings.getDialect(),
                        settings.getDefaultCatalogName(), settings.getDefaultSchemaName(), (RootClass) model);
               
                String entityName = model.getEntityName();
                identifierGenerators.put(entityName, generator);
               
                //hack 1: identifier would ordinarily be SimpleValue but this is not part of the public API
                if (identifier instanceof SimpleValue)
                {
                    SimpleValue sv = (SimpleValue) identifier;
                    sv.setIdentifierGeneratorProperties(null);
                    sv.setIdentifierGeneratorStrategy("assigned");
                }
               
            }
           
        }

    }
   
    public IdentifierGenerator getIdentifierGenerator(Object target)
    {
        return identifierGenerators.get(target.getClass().getName());
    }
   

}


3) create factory methods for each of the domain classes, instead of using the "new" operator. The id is added in the factory method

Code:
public Project newProject()
{
    final Project project = new Project();
    Long objectIdentifier = (Long) getObjectIdentifier(project);
    project.setProjectId((objectIdentifier).longValue());
    return project;
}

private Serializable getObjectIdentifier(final Object object)
{

    HibernateSessionFactoryBean sessionFactoryBean = (HibernateSessionFactoryBean) context
            .getBean(BeanFactory.FACTORY_BEAN_PREFIX + SpringBeans.sessionFactory);

    //pick up the identifier generator being used in the application
    final IdentifierGenerator identifierGenerator = sessionFactoryBean.getIdentifierGenerator(object);
   
    return (Serializable) hibernateDaoSupport.getHibernateTemplate().execute(new HibernateCallback()
    {
        public Object doInHibernate(Session session) throws HibernateException, SQLException
        {
            return identifierGenerator.generate((SessionImplementor) session, object);
        }
    }, true);

}


There are a couple of obvious issues: the IdentifierGenerator API is designed to be used internally, not by the application. That's why I'm having to cast to SessionImplementor. I'm also having to cast to SimpleValue in the postProcessConfiguration() method.

Nevertheless, it may still be worth it. At least I can have very simple identifier based implementations of hashCode() and equals(), which means fewer opportunities for bugs here.

It would be nice if the identifier generator API were public and what I'm doing here were an "approved" option.


Top
 Profile  
 
 Post subject: Re: Using Hibernate to generate primary keys on object creat
PostPosted: Wed Aug 24, 2005 6:56 am 
Senior
Senior

Joined: Tue Aug 03, 2004 2:11 pm
Posts: 142
Location: Somerset
pzoio wrote:
I am experimenting with an alternative approach to primary key generation and would welcome any comments on it.


Why not use surrogate keys as your primary keys (i.e. identity columns) ?

_________________
On the information super B road


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 24, 2005 8:35 am 
Newbie

Joined: Thu Nov 25, 2004 11:44 am
Posts: 15
Location: Woodbridge UK
Yes, I am in fact using surrogate keys for all my persistent classes. Its just a question as to when the key property gets populated.

My idea is to populate it at the beginning of the logic "create new entity" operation (before it gets added to any collections), rather than automatically at the time of saving.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 24, 2005 1:08 pm 
Senior
Senior

Joined: Tue Aug 03, 2004 2:11 pm
Posts: 142
Location: Somerset
pzoio wrote:
Yes, I am in fact using surrogate keys for all my persistent classes. Its just a question as to when the key property gets populated.

My idea is to populate it at the beginning of the logic "create new entity" operation (before it gets added to any collections), rather than automatically at the time of saving.


The surrogate keys should get populated automatially by the database. You define it as an identity column within the hibernate mapping file, and that's it, you never, ever, do anything about populating it in your application code, part from setting it to some initial value (the "unsaved" value in the hibernate mapping) which is normally null if your surrogate key is for isntance, and Integer in your POJO and an INTEGER on the database.

There is pretty much a whole chapter discussing this, as well as the concept of business keys, in "Hibernate in Action", which I really should be getting commission for, the number of times I am mentioning it.

_________________
On the information super B road


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 24, 2005 2:15 pm 
Newbie

Joined: Thu Nov 25, 2004 11:44 am
Posts: 15
Location: Woodbridge UK
I think you're misunderstanding the purpose of what I'm suggesting here.

I understand the concept of business key, and why its "needed". The purpose of the primary key is to represent identity for a database row. The fact that you need to represent identity another way (by a combination of other fields - your business key) is an additional restriction on your object model which I'm not entirely comfortable with. It doesn't fit very well with the circumstances I'm currently in.

My idea is that if you retrieve the primary key early enough in an object's life cycle, then I think you can get around this restriction and not have to worry about the business key at all. I appreciate that there are other compromises you have to make to do this - and that I'm trying to do is determine whether there are enough good reasons not to do this to put me off the idea.

btw - I do have copy of Hibernate in Action which I've read in detail - several times in parts


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 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:
cron
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.