-->
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: parameterized user types + HQL = trouble
PostPosted: Sun Sep 04, 2005 4:38 pm 
Newbie

Joined: Sun Oct 05, 2003 6:23 pm
Posts: 3
Hibernate version: 3.0.5

I've been playing around with custom parameterized user types a bit. I'm using the EnumUserType code from the website (http://hibernate.org/272.html). It works well with CRUD cases, but when you start to use these types with HQL, it seems to fall apart a bit.

Say you have an object Glass, which has an enum in it called State. So the mapping file would look like:

Code:
<hibernate-mapping>
   <typedef name="state" class="EnumUserType">
        <param name="enumClassName">example.State</param>
   </typedef>

   <class table="Glass" class="example.Glass">
        <id name="id" column="Id" type="int">
          <generator class="native" />
        </id>

       <property name="state" column="State" type="state" />
   </class>
</hibernate-mapping>


Then the class:

Code:
public class Glass {
    private State state;
    public State getState() { return state; }
    public void setState(State state) { this.state = state; }
}

public enum State {
    FULL, HALF_FULL, HALF_EMPTY, EMPTY;
}
}


Saving, updating, deleting all works fine. But if I try to do an HQL query:

Code:
session.createQuery("from Glass glass where glass.state=:state").setParameter("state", State.FULL).list();


That doesn't work. ':state' will be replaced with a serialized version of the enum, because Hibernate doesn't know what type it is (and an enum is Serializable). And you can't do this either:

Code:
session.createQuery("from Glass glass where glass.state=:state").setParameter("state", State.FULL, Hibernate.custom(EnumUserType.class).list();


Hibernate.custom() will create a new instance of EnumUserType which will need the same parameters from the typedef. I guess you could add the parameters in the call to Hibernate.custom, but thats not very satisfying because you'll have places where you are defining the type, the mapping file and the code.

Assuming I'm not missing anything, it seems that the two ways to fix this are:

1) to create Hibernate.custom(String typedefName). That way you can reference that original typedef that you created.

2) A better solution would be to have Hibernate infer what the UserType should be based on the property you're referencing. So in this case, it should know that 'glass.state' is of type 'state', so the value object must be something that can be handled by that UserType class.


Any thoughts?

--Alex


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 05, 2005 4:29 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
We thought about that already. Solution 2 is the right solution but pretty complex to do, since the recovery has to be contextual (ie query contextual).
In the meanwhile you have to do
.setParameter( "state", state.ordinal() ); or .setParameter( "state", state.name() ); depending of the underlying column

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 29, 2005 2:33 pm 
Beginner
Beginner

Joined: Fri Jul 08, 2005 8:09 am
Posts: 28
I have a similar problem, my user type maps a SQL Date column to a custom class, say, MyTimestamp. Reading and writing work good, but HQL parameters pose a problem. Consider this query:

Code:
      session.createQuery("from Event e where e.start < ?")
        .setParameter(0, MyTimestamp.now())
        .list();


This is rejected by Oracle with an "incompatible columns" error. I tried to use a string representation (.setString(0, "TO_DATE(...)")) but cannot insert this string as parameter for obvious reasons, the statement parameter cannot contain functions. The only thing which helped was a type conversion like this:

Code:
      session.createQuery("from Event e where e.start < ?")
        .setTimestamp(0, MyTimestamp.now().toSqlTimestamp())
        .list();


It is rather ugly. Is there a better way?

Regards


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 30, 2005 4:42 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
you have a setParameter(String, Date, TemporalType)

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 30, 2005 5:33 am 
Beginner
Beginner

Joined: Fri Jul 08, 2005 8:09 am
Posts: 28
Thanks, but that did not work because MyTimestamp is not derived from Date or other date/time classes. I assume I would need a specific implementation for the Type interface. But the advantage is marginal as opposed to the current manual conversion into java.sql.Timestamp. But thanks anyway.


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:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.