-->
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.  [ 2 posts ] 
Author Message
 Post subject: composite-element with BLOB/CLOB type
PostPosted: Fri Dec 05, 2003 11:44 am 
Newbie

Joined: Sat Sep 06, 2003 8:49 pm
Posts: 8
I'm trying to map some sets in my application. I'm using the hbmtojava and hbmtoddl utilities to generate the java beans and ddl for the database (mysql). What I have is something like this:

BuildRequest is a top level element which the application deals with.
A BuildRequest can contain several comments.
A BuildRequest can contain several interestedUsers.

Originally I tried mapping them like in BuildRequest:
Code:
      <set name="comments"
          inverse="true"
          order-by="createDate"
          cascade="all-delete-orphan">
         <key column="request_id"/>
         <one-to-many class="model.RequestComment"/>
      </set>

      <set name="interestedUsers"
          inverse="true"
          cascade="all-delete-orphan">
         <key column="request_id"/>
         <one-to-many class="model.InterestedUser"/>
      </set>

Here is the mapping for RequestComment:

Code:
<hibernate-mapping>         
   <class name="model.RequestComment"
         table="request_comment">

      <id name="id" column="id" type="int">
         <generator class="hilo"/>
      </id>

      <many-to-one name="request"
                class="model.BuildRequest"
                column="request_id"
                not-null="true"/>               
                      
      <property name="comment" type="model.TextType">
         <column name="commentText" sql-type="text" not-null="true"/>
      </property>

      <property name="author" type="string">
         <column name="author" sql-type="varchar(64)" not-null="true"/>
      </property>
      
      <property name="createDate" type="timestamp">
         <column name="createDate" sql-type="datetime" not-null="true"/>
      </property>
   </class>   
</hibernate-mapping>


Interested User:

Code:
<hibernate-mapping>         
   <class name="model.InterestedUser"
         table="interested_user">
      
      <id name="id" column="id" type="int">
         <generator class="hilo"/>
      </id>

      <many-to-one name="request"
                class="model.BuildRequest"
                column="request_id"
                not-null="true"/>               
                        
      <property name="user" type="string">
         <column name="userName" sql-type="varchar(64)" not-null="true"/>
      </property>
   </class>   
</hibernate-mapping>

This id key strategy worked fine for RequestComment. But for InterestedUser I really wanted the key to be request_id, userName, don't want to duplicate userids for the same request.

So I started looking into composite-ids

replace above InterestedUser mapping with:
Code:
   <composite-id>
         <key-many-to-one name="request"
                       class="model.BuildRequest"
                       column="request_id"/>               

         <key-property name="user" type="string">
            <column name="userName" sql-type="varchar(64)" not-null="true"/>
         </key-property>
      </composite-id>

This gave me the mapping I wanted, BUT I could never get it to insert/update properly. It would not insert without using
unsaved-value="any" I think because the key was not null?(does that make sense) I then used the unsaved-value="any" and
everytime I updated a BuildRequest, it would attempt to re-insert the InterestedUsers and get key constraint violations.
So I even went so far as to write an Interceptor and override isUnsaved method, but it turns out I couldn't tell which
ones weren't saved without actually going to the DB and looking for them (not very elegant in my opinion).

Which lead me to read about composite-elements. SO here is the latest greatest mapping:

Code:
<hibernate-mapping>         
   <class name="model.BuildRequest"
         table="build_request">
      <id name="id" column="id" type="int">
         <generator class="hilo"/>
      </id>

      <!-- a null priority will indicate complete -->
      <property name="priority" type="int">
           <column name="priority" sql-type="int"/>
      </property>

      <property name="application" type="string">
         <column name="application" sql-type="varchar(64)" not-null="true"/>
      </property>

      <property name="requestor" type="string">
         <column name="requestor" sql-type="varchar(64)" not-null="true"/>
      </property>
      
      <property name="engineer" type="string">
         <column name="engineer" sql-type="varchar(64)"/>
      </property>

      <property name="request" type="model.TextType">
         <column name="request" sql-type="text" not-null="true"/>
      </property>

      <property name="submitDate" type="timestamp">
         <column name="submitDate" sql-type="datetime" not-null="true"/>
      </property>

      <property name="requestByDate" type="timestamp">
         <column name="requestByDate" sql-type="datetime" not-null="true"/>
      </property>

      <property name="startDate" type="timestamp">
         <column name="startDate" sql-type="datetime"/>
      </property>

      <property name="doneDate" type="timestamp">
         <column name="doneDate" sql-type="datetime"/>
      </property>

      <property name="silent" type="boolean">
         <!-- MySql does not support boolean -->
         <column name="silent" sql-type="int" not-null="true"/>
      </property>

      <property name="status"
              type="model.RequestStatusEnum"
              not-null="false"
              unique="false"
              update="true"
              insert="true">
           <column name="status" sql-type="int" not-null="true" />
        </property>      

      <property name="type"
              type="model.RequestTypeEnum"
              not-null="false"
              unique="false"
              update="true"
              insert="true">
           <column name="type" sql-type="int" not-null="true" />
        </property>        
      
      <set name="comments" table="request_comment" lazy="true">
         <key column="request_id"/>
         <composite-element
            class="model.RequestComment">
            <property name="comment" type="model.TextType">
               <column name="commentText" sql-type="text" not-null="true"/>
            </property>
      
            <property name="author" type="string">
               <column name="author" sql-type="varchar(64)" not-null="true"/>
            </property>
            
            <property name="createDate" type="timestamp">
               <column name="createDate" sql-type="datetime" not-null="true"/>
            </property>
         </composite-element>
      </set>

      <set name="interestedUsers" table="interested_user" lazy="true">
         <key column="request_id"/>
         <composite-element
            class="model.InterestedUser">      
            <property name="user" type="string">
               <column name="userName" sql-type="varchar(64)" not-null="true"/>
            </property>            
         </composite-element>
      </set>

   </class>      
</hibernate-mapping>

This looks like what I want EXCEPT that the composite-element for RequestComment has a BLOB/CLOB type in it. Since ALL the
fields of a composite-element are used for a key I get the following when exporting the schema:

[schemaexport] Unsuccessful: General error, message from server: "BLOB column '
commentText' used in key specification without a key length"

So my question is this. Are composite-elements the right approach? Should I use composites for InterestedUsers and a
standard many-to-one for RequestComments? Is there a work around?

Thanks in advance!
--m


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 05, 2003 7:22 pm 
Newbie

Joined: Sat Sep 06, 2003 8:49 pm
Posts: 8
Thanks to all who read. My solution has been to declare the "set" of RequestComments as a "bag" instead. Changes the backing collection that is generated from a java.util.Set to a java.util.List so not a huge code impact. Also, using a bag does not create a primary key in the generated sql(so no pk errors), and it fits my semantics good enough.


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