-->
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: list-index and one-to-many mapping
PostPosted: Wed May 30, 2007 8:53 pm 
Newbie

Joined: Sat May 19, 2007 12:02 pm
Posts: 19
Hibernate Documentation is not very clear about this !

Code:
<list-index
        column="column_name"                (1)
        base="0|1|..."/>

    (1)
    column_name (required): The name of the column holding the collection index values.
    (1)
    base (optional, defaults to 0): The value of the index column that corresponds to the first element of the list or array.


The question is, why do I need to specify the column name ? How can I get a list with indeces 0.....* ?
And if the column name is imortant why do I need a base ?
Any link to a tutorial or example will do it.

Thanx


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 30, 2007 9:28 pm 
Newbie

Joined: Tue May 08, 2007 8:43 pm
Posts: 5
I'll reference myself for this one... I asked a related question in http://forum.hibernate.org/viewtopic.php?t=974248 (to which unfortunately I haven't received any answer - I moreorless have figured it out myself anyway).


Quote:
Suppose you have two model objects : Page and Line. A page may have multiple lines, and a line must belong to exactly one page. I also want to put some ordering on the lines of a pages, since I obviously don't want them to appear in a random fashion. So far, I have the following tables (simplified for the sake of the example; the underlined columns are the primary keys) :
    Page (page_id)

    Line (line_id, page_id, line_number)

The "number" column identifies the position of a given line on a page. I assume there is no such thing as a "null" line, so the "number" values of the lines of any page is sequential (it won't be possible to have for a given page a line with number=3, another with number=5 but nothing with number=4). Also notice that (page_id, number) would be a perfectly valid composite primary key, but I chose to use a surrogate key instead. I added a constraint in my database that ensures the uniqueness of (page_id, line_number).



Some samples tuples for your table Line would be:

Code:
line_id | page_id | line_number
---------+---------+-------------
       1 |       1 |           1
       2 |       2 |           1
       3 |       3 |           1
       4 |       3 |           2
       5 |       4 |           1
       7 |       4 |           2
      10 |       4 |           3


Now this situation is a perfect candidate for list mapping, because there is a sequential ordering of the lines of a page.

In this specific case, the index column is "line_number". There is no way Hibernate could guess beforehands which column should be your index.


The base specifies where your index starts in the database (here it would be 1). This is important because you may have decided that your list is 1-based for instance in your database (like in this example); however, Java lists are always 0-based.

If you specify base="0" but you actually start counting at 1, you would get a null when trying to access page.getLines().get(0) because there is no entry in Line with line_number = 0 - possibly raising NullPointerException afterwards when trying to access your lines.

However, if you indicate that your mapping is "1"-based, then Hibernate will shift the indexes such that page.getLines().get(0) points to the line entry with line_number = 1.

In other word, your base specifies by how much Hibernate should shift the value of the index column (in + ou - depending on which way you're going) to map it to the indexes of your Java list.

A working mapping for this example would be :

Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="test">
   <class name="Page" table="PAGE">
      <id name="id" column="page_id">
         <generator class="native">
            <param name="sequence">page_page_id_seq</param>
         </generator>
      </id>
      
      <property name="number" column="page_number" insert="false" update="false"/>
      
      <list name="lines" lazy="false" cascade="all">
         <key column="page_id" not-null="true"/>
         <list-index base="1" column="line_number"/>
         <one-to-many class="Line"/>
      </list>
   </class>
</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 30, 2007 10:18 pm 
Newbie

Joined: Sat May 19, 2007 12:02 pm
Posts: 19
That was a lot of help thank you. If the documentation mentioned anything about when to use each collection type (ie. list for sequential) it would have been way better. In my case I have Account --> Invoice mapping, so there will be gaps. I think I'll try to find another way to do the mapping here, may be bag.

Thanks alot.


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 30, 2007 11:04 pm 
Newbie

Joined: Tue May 08, 2007 8:43 pm
Posts: 5
You're welcome! In your case and based on what I understand, what would probably make sense would be a sorted bag mapping. If you provide more details about what you need and what your data structure is, I'll be able to confirm this suggestion (or not).


Here are a few guidelines to help you choose between set/bag/list/map mappings:

    - use a list mapping + List when you have a sequential index (and only in this case)

    - use a map mapping + Map when you need to represents things as a (key, value) mapping; this usually makes sense when your 'index' column is not a sequential integer (eg a String, an enum, ...) and/or when your key has a special meaning beyond indexing results

    - use a set mapping + Set if you need an set of elements (unordered, unique values)

    - use a bag for the rest:

      * if you need to handle multisets (unordered, non-unique values), use a bag mapping backed by a List (but do NOT attach any meaning to the ordering of that list as it won't be reflected in the db)

      * if you need ordered sets (which a set mapping cannot provide to my knowledge - a set mapping backed up by a TreeSet can provide sorted elements, but not ordered elements), use a bag mapping (specifying an "order-by" directive in your mapping file) backed by a TreeSet


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 31, 2007 6:36 pm 
Newbie

Joined: Sat May 19, 2007 12:02 pm
Posts: 19
I have accounts that I need to map to an invoices. The structure of these tables:


Code:
mysql> describe Account ;
+-----------+--------------+------+-----+---------+----------------+
| Field     | Type         | Null | Key | Default | Extra          |
+-----------+--------------+------+-----+---------+----------------+
| id        | int(11)      | NO   | PRI | NULL    | auto_increment |
| firstName | varchar(64)  | NO   |     |         |                |
| lastName  | varchar(64)  | NO   |     |         |                |
| address   | varchar(128) | NO   |     |         |                |
| phone     | varchar(32)  | NO   |     |         |                |
| fax       | varchar(32)  | NO   |     |         |                |
| email     | varchar(64)  | NO   |     |         |                |
+-----------+--------------+------+-----+---------+----------------+

mysql> describe Invoice ;
+---------------+-----------+------+-----+-------------------+----------------+
| Field         | Type      | Null | Key | Default           | Extra          |
+---------------+-----------+------+-----+-------------------+----------------+
| id            | int(11)   | NO   | PRI | NULL              | auto_increment |
| customerID    | int(11)   | NO   |     |                   |                |
| statementDate | timestamp | NO   |     | CURRENT_TIMESTAMP |                |
| paidAmount    | float     | NO   |     |                   |                |
| retainer      | float     | NO   |     |                   |                |
| amountPaid    | float     | YES  |     | NULL              |                |
| accId         | int(11)   | YES  | MUL | NULL              |                |
+---------------+-----------+------+-----+-------------------+----------------+
7 rows in set (0.00 sec)



I just tried using Set, it's ok for now. I am stil discovering.
Thank you.


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.