-->
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.  [ 6 posts ] 
Author Message
 Post subject: Best way to handle unique properties
PostPosted: Fri Oct 08, 2004 8:20 pm 
Beginner
Beginner

Joined: Fri Jul 30, 2004 2:53 pm
Posts: 33
Location: Washington, DC
What is the best way to handle unique properties? For example, say I have a user object that has a iterator generated PK. Also, I have a unique not null "username" property on my user object, so 2 different user objects can't have the same username. One way to handle this would be to query the DB, see if there already is a record with that username, if so, throw an exception, otherwise create the record. Is there a better way to handle this with hibernate?


Top
 Profile  
 
 Post subject:
PostPosted: Sat Oct 09, 2004 9:45 am 
Newbie

Joined: Thu Sep 25, 2003 7:21 pm
Posts: 17
you can add a UNIQUE database constraint to the column, if you're using hbm2ddl to generate your schema you can add unique="true" attribute to your property like this

Code:
<property
    name="username"
    column="username"
    unique="true"
/>


now the ddl generated will include a unique constraint, additionally it will allow hibernate to give you more sensible error messages


Top
 Profile  
 
 Post subject:
PostPosted: Sat Oct 09, 2004 11:43 am 
Beginner
Beginner

Joined: Fri Jul 30, 2004 2:53 pm
Posts: 33
Location: Washington, DC
Ok, I am using hibernate 2.1.6 & hsqldb 1.7.2. My mapping looks like this:
Code:
<hibernate-mapping>
    <class name="my.package.model.User" table="users">
        <id name="id">
            <generator class="increment"/>
        </id>
        <property name="username">
            <column name="username" length="16" not-null="true" unique="true"/>
        </property>
        <property name="password"/>
        <property name="firstName"/>
        <property name="lastName"/>
        <property name="email"/>
    </class>
</hibernate-mapping>

I am using Spring, so my dao looks like this:
Code:
    public void save(User user) {
        getHibernateTemplate().saveOrUpdate(user);
    }

I have a test like this:
Code:
        try {
            User user = new User();
            user.setUsername("pbarry");
            dao.save(user);
        } catch(Exception ex) {
            log.error(ex);
            throw ex;
        }

pbarry already exists in the DB. Here is what I get in log:
Code:
11:27:38,595 - DEBUG - net.sf.hibernate.util.JDBCExceptionReporter - SQL Exception
java.sql.BatchUpdateException: failed batch
   at org.hsqldb.jdbc.jdbcStatement.executeBatch(Unknown Source)
   at org.hsqldb.jdbc.jdbcPreparedStatement.executeBatch(Unknown Source)
   at net.sf.hibernate.impl.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:54)
   at net.sf.hibernate.impl.BatcherImpl.executeBatch(BatcherImpl.java:126)
   at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2421)
   at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2371)
   at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2240)
   at org.springframework.orm.hibernate.HibernateAccessor.flushIfNecessary(HibernateAccessor.java:214)
   at org.springframework.orm.hibernate.HibernateTemplate.execute(HibernateTemplate.java:177)
   at org.springframework.orm.hibernate.HibernateTemplate.saveOrUpdate(HibernateTemplate.java:317)
   at my.package.dao.impl.UserDAOImpl.save(UserDAOImpl.java:21)
   at my.package.dao.UserDAOTest.testSaveNewDup(UserDAOTest.java:91)
    ...

Is BatchUpdateException the correct exception? Shouldn't it be something that indicates the unique constraint has been violated? For example, If I change the code to not use hiberate at all, like this:
Code:
        try {
           DataSource ds = (DataSource)context.getBean("dataSource");
           Connection con = ds.getConnection();
           PreparedStatement ps = con.prepareStatement(
               "INSERT INTO users (id,username) VALUES (?,?)");
           ps.setInt(1,8);
           ps.setString(2,"pbarry");
           ps.executeUpdate();
        } catch(Exception ex) {
            log.error(ex);
            throw ex;
        }

The log has this:
Code:
java.sql.SQLException: Unique constraint violation: SYS_CT_127 in statement [INSERT INTO users (id,username) VALUES (?,?)]

So is this a hibernate misconfiguration or error on my part or is there a bug here?


Top
 Profile  
 
 Post subject:
PostPosted: Sat Oct 09, 2004 8:06 pm 
Newbie

Joined: Thu Sep 25, 2003 7:21 pm
Posts: 17
This just means that hibernate is using batch updates behind the scenes. Batch updates send multiple queries to the database at a time this reduces the number of JDBC calls and improves performance, the exception you mentioned extends SqlException so you can still get the error code


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 11, 2004 12:04 am 
Newbie

Joined: Fri Jul 30, 2004 4:17 am
Posts: 5
Location: Sydney, Australia
I was told before that you should query with Hibernate, trying to load up the same user, and throw your own UserAlreadyExists exception.

I don't really understand say why hibernate doesn't have its own UniqueConstraint exception?
maybe it doesn't want to rely on support from the underlying database.

is the unique attribute only for generating ddl? The online docs don't even mention the unique attribute for a standard property mapping element.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 11, 2004 2:23 am 
Expert
Expert

Joined: Thu Jan 29, 2004 2:31 am
Posts: 362
Location: Switzerland, Bern
There's one important thing to know: If you get an exception from a session you have to rollback your transaction and close the session (see http://forum.hibernate.org/viewtopic.php?t=933515 for exceptions of this rule). But that's not all, you cannot savely do something like that:

Code:
try {
   session.save(user)
}
catch (Hibernate or sql Exception) {
   user.setName("an other name");
   session = HibernateUtil.getSession();
   session.save(user);
   ....
}


If this is fine for you, just relay on the unique constraint of the db. If you need a second chance to save the same object you must do your unique check in the DAO on top of hibernate. (Of course you can use HQL to query for the new name.)

See http://forum.hibernate.org/viewtopic.php?t=933495 for more details.

HTH
Ernst


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 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.