-->
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: Trouble modifying order of parent/child many-to-many.
PostPosted: Mon Mar 06, 2006 10:50 am 
Beginner
Beginner

Joined: Tue Dec 21, 2004 5:34 pm
Posts: 25
I'm having trouble with a collection mapping that I hope the Hibernate community can help me out with.

I have a Person class that has a reflexive relationship. Below are some requirements of the mapping.

A Person has one and only one parent(Person).
A Person has many children(Person).
A Person can be a child of many Persons.

All in all I believe I have a unidirectional many-to-one from Person to parent and a unidirectional from Person to children. I believe this is right but not positive (not positive because I'm having issues). The tricky part to this relationship is that a child knows of only one parent but does not know the Persons that it’s a child for. Let’s look at the code.

I have two tables:

person: for the Person class with a parent_id column which is the foreign key to itself.

Code:
CREATE TABLE person (
  id CHAR(32) NOT NULL,
  parent_id char(32),
  name VARCHAR(255) NOT NULL,
  descr VARCHAR(255),
  PRIMARY KEY pk_person (id)
)

ALTER TABLE person ADD CONSTRAINT fk_parent_person
    FOREIGN KEY (parent_id) REFERENCES person (id);


person_link: a link table for my relationship (many-to-many collection) that has a 'branch_id', 'leaf_id', and 'sequence' column. 'branch_id' represents the parent, 'leaf_id' represents the child and 'sequence' for the order of the list collection they are mapped to.

Code:
CREATE TABLE person_link (
  branch_id CHAR(32) NOT NULL,
  leaf_id CHAR(32) NOT NULL,
  sequence INT,
  PRIMARY KEY pk_person_link (branch_id, leaf_id)
)

ALTER TABLE person_link ADD CONSTRAINT fk_branch_person
    FOREIGN KEY (branch_id) REFERENCES person (id);

ALTER TABLE person ADD CONSTRAINT fk_leaf_person
    FOREIGN KEY (leaf_id) REFERENCES person (id);



Here's a snipit of my Parent class.

Code:
public class Parent {

  ...

  private Person parent;
  private List<Person> children;

  ...
}



Snipit of the mapping.

Code:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

   ...

    <many-to-one name="parent" class="com.xyz.Parent"
      column="parent_id" />

    <list name="children" table="person_link" cascade="save-update"
      lazy="true">
      <key column="branch_id" />
        <list-index column="sequence" />
        <many-to-many class="com.xyz.Parent" column="leaf_id" />
    </list>

  ...



I can add and delete to the collection just fine. It's when I want to change the order of the collection is when I have issues.

The code I use to change the order follows:

Code:
Collections.swap(person.getChildren(), index, index-1);

personDao.store(person);


I get the following exception:

Code:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: Hibernate operation: Could not execute JDBC batch update; SQL [update person_link set leaf_id=? where branch_id=? and sequence=?]; Duplicate entry '40288fe509a271ff0109a272038a0002-40288fe509a7d78f0109a7d88c47000' for key 1; nested exception is java.sql.BatchUpdateException: Duplicate entry '40288fe509a271ff0109a272038a0002-40288fe509a7d78f0109a7d88c47000' for key 1
   org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:406)
   org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:348)
   javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
   javax.servlet.http.HttpServlet.service(HttpServlet.java:802)


My only thought after writing this up was that there may be something I don't understand in regards to lazy loading. Might have to eager fetch this to actually change the order.

Any thoughts?


Thanks in advance.

Hibernate version:
3.1.2

Name and version of the database you are using:
MySQL: 5.0.18
MySQL JDBC: 3.1.12[/code]


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 06, 2006 5:51 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Your uniqueness constraint (primary key constraint) is obviously confusing HIbernate. You've got Parent X, Child Y, index 1; Parent X, Child Z, index 2. When you try to swap these, the first thing HIbernate does is set Parent X, Child Z, index 1: voila, uniqueness constraint violation, one Parent with Child Z twice (index 1 and 2). Hibernate was going to immediately follow that update by setting Parent X, Child Y, index 2, thus fixing the situations, but the DB has already barfed.

You could delete one child then reinsert in the correct place. I don't think it's possible to get Hibernate to update indices and keep references in place, instead of the other way around like it's doing now. If you wanted to avoid the extra delete (delete/insert instead of just update), you could stop using <list>, and just use <set> with a join table/composite element, being the index. The purchasedItems example in section 8.2. "Collections of dependent objects" of the ref docs explains this approach.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 07, 2006 3:20 pm 
Beginner
Beginner

Joined: Tue Dec 21, 2004 5:34 pm
Posts: 25
Thanks for the reply.

I think I'm going to stick with my pk setup. I want to keep that integrity with my data. So I’ll probably delete the child I want to reorder and re-add where I want it to go.

I believe I understand your suggestion about components but I'm thinking that this just complicates my relationship. In response to that I have some questions:

1. Is there something about my relationship that is not straight forward? In general I feel that this is a simple relationship but I feel I have to work around Hibernate. It doesn't appear to me that just to change the order of my collection I'd have to programmatically delete and re-add a child in the collection.

2. Is there a better way of mapping a relationship like this and still use the Collections.swap() method and the db constraints? Am I missing the big picture?

Thanks again.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 07, 2006 4:32 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
The problem is that hibernate's <list> mapping relies on unsaved-value and other such attributes to determine when a list-index needs to be generated. I don't know how hibernate handles renumbering an already-saved list member. It probably does handle it, but there may be some mapping niceties needed that I'm not aware of. You could play around with your test case, and if you get it to work, post here.

If the list index is an "important" value to your app, I'd recommend using a map and making the list-index into the map-index. I know that maps work the way you want them to, thoguh obviously without the list/swap functionality. But you can do this:
Code:
Type var = map.get(Integer.valueOf(10));
map.put(Integer.valueOf(10), map.get(Integer.valueOf(11)));
map.put(Integer.valueOf(11), var);


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 08, 2006 3:38 pm 
Beginner
Beginner

Joined: Tue Dec 21, 2004 5:34 pm
Posts: 25
tenwit wrote:
The problem is that hibernate's <list> mapping relies on unsaved-value and other such attributes to determine when a list-index needs to be generated. I don't know how hibernate handles renumbering an already-saved list member. It probably does handle it, but there may be some mapping niceties needed that I'm not aware of. You could play around with your test case, and if you get it to work, post here.

If the list index is an "important" value to your app, I'd recommend using a map and making the list-index into the map-index. I know that maps work the way you want them to, thoguh obviously without the list/swap functionality. But you can do this:
Code:
Type var = map.get(Integer.valueOf(10));
map.put(Integer.valueOf(10), map.get(Integer.valueOf(11)));
map.put(Integer.valueOf(11), var);


Another clever idea. I'll keep this in mind for future consideration. Again I think I will stick with the delete and re-add. I will post a working example time permitting. It will be easier for me to stick with what I have considering I would have to change my code in quite a few spots. Again thanks for the help.

The one question I feel I still don't have an answer to is:
Quote:
1. Is there something about my relationship that is not straight forward? In general I feel that this is a simple relationship but I feel I have to work around Hibernate. It doesn't appear to me that just to change the order of my collection I'd have to programmatically delete and re-add a child in the collection.


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.