-->
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.  [ 12 posts ] 
Author Message
 Post subject: bidi association: bug or my mistake
PostPosted: Sat Aug 20, 2005 1:41 am 
Newbie

Joined: Mon Jun 20, 2005 12:20 pm
Posts: 17
[code]
<class name="AbstractObjectDB" abstract="true" polymorphism="implicit" >
<id name="objectID" column="object_id" unsaved-value="0">
<generator class="increment" />
</id>

<property name="state" column="state" type="short" />
<many-to-one name="projectDB" column="project_id" class="ProjectDB"/>
...
<union-subclass name="BaseObjectDB" table="object">
....
<union-subclass name="AbstractPropertyDefinitionDB" abstract="true">
<property name="name" type="string">
....
<union-subclass name="BooleanPropertyDefinitionDB" table="bool_property_definition">
<property name="defaultBoolean" column="bool_value" type="boolean" />
</union-subclass>
</union-subclass>
...
<union-subclass name="ProjectDB" table="project">
<set name="propertyDefinitions" inverse="true" cascade="all-delete-orphan">
<key column="project_id"/>
<one-to-many class="AbstractPropertyDefinitionDB" />
</set>
</union-subclass>
</union-subclass>
</class>
[/code]

The above mapping generates the following schema:

[code]
create table bool_property_definition (
object_id bigint not null,
state smallint,
project_id bigint,
...
name varchar(255) not null,
project_id bigint,
bool_value bit,
primary key (object_id)
);
[/code]


There are duplicated project_id columns. Please help! Thanks,

ZJ


Top
 Profile  
 
 Post subject: It is hibernate limitation
PostPosted: Sun Aug 21, 2005 12:15 am 
Newbie

Joined: Mon Jun 20, 2005 12:20 pm
Posts: 17
After having played around for 24 hours, I found that hibernate could not handle this case properly. If I move the many-to-one association

<many-to-one name="projectDB" column="project_id" class="ProjectDB"/>

from AbstractObjectDB class to the concreate class BooleanPropertyDefinitionDB, then everything is fine.

However, I believe that the many-to-one association should be defined in the base class because:

1. projectDB is declared in the base class (bstractObjectDB),
2. the many-to-one association only needs to be defined once, and
3....

Could some hibernate gurus please give me some explaination?

Thanks,
ZJ


Top
 Profile  
 
 Post subject: simplified
PostPosted: Sun Aug 21, 2005 4:40 pm 
Newbie

Joined: Mon Jun 20, 2005 12:20 pm
Posts: 17
I tried to simplify the problem with 3 simple classes:

public abstract class AbstractItem implements Serializable {
public static final long serialVersionUID = 1L;

protected long itemID;
Container container;

public AbstractItem() {
}

public long getItemID() {
return itemID;
}

public void setItemID(long objectID) {
this.itemID = objectID;
}

public Container getContainer() {
return container;
}

public void setContainer(Container container) {
this.container = container;
}
}

public class Container extends AbstractItem {
Set parts;

public Container() {
}

public Set getParts() {
return parts;
}

public void setParts(Set parts) {
this.parts = parts;
}
}

public class Part extends AbstractItem {
String name;

public Part() {
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

and mapping file:

<class name="AbstractItem" abstract="true" polymorphism="implicit" >
<id name="itemID" column="item_id" unsaved-value="0">
<generator class="increment" />
</id>
<many-to-one name="container" column="container_id" class="Container"/>
<union-subclass name="Part" table="part">
<property name="name" column="part_name" type="string" />
</union-subclass>
<union-subclass name="Container" table="container">
<set name="parts" inverse="true" cascade="all-delete-orphan">
<key column="container_id"/>
<one-to-many class="Part" />
</set>
</union-subclass>
</class>

It generated the following schema:

create table container (
item_id bigint not null,
container_id bigint,
primary key (item_id)
);

create table part (
item_id bigint not null,
container_id bigint,
part_name varchar(255),
container_id bigint,
primary key (item_id)
);

Is it a hiberante bug? any solution? I really want to use union-subclass.

ZJ


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 22, 2005 9:52 am 
Regular
Regular

Joined: Thu Apr 14, 2005 2:15 pm
Posts: 66
Hi, I've been trying to solve you problem for some days and now I understand what's happened. There is nothing wrong with hibernate!
One project_id column is generated to reference the many-to-one association of superclass. Rename it to abstract_project_id to see the diference in the generated ddl.
The another project_id is to reference the set.

Look the possible solution below:

Code:
<class name="AbstractItem" abstract="true" polymorphism="implicit">
   
   <id name="itemID" column="item_id" unsaved-value="0">
      <generator class="increment" />
   </id>
   
   <many-to-one name="container" column=[b]"container_id_abstract"[/b]
      class="Container" />
   <union-subclass name="Part" table="part">
      <property name="name" column="part_name" type="string" />
   </union-subclass>
   <union-subclass name="Container" table="container">
      <set name="parts" inverse="true" cascade="all-delete-orphan">
         <key column=[b]"container_id_part"[/b] />
         <one-to-many class="Part" />
      </set>
   </union-subclass>
</class>


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 22, 2005 10:14 am 
Newbie

Joined: Mon Jun 20, 2005 12:20 pm
Posts: 17
Hi Ronald,

Thank you for sharing your idea. I understand where the extra column come from. However, I think that hibernat creates an undeeded extra column. As you may see, there is no the extra column created if I put the many-to-one association inside the Part union-subclass, e.g.

<class name="AbstractItem" abstract="true" polymorphism="implicit">

<id name="itemID" column="item_id" unsaved-value="0">
<generator class="increment" />
</id>

class="Container" />
<union-subclass name="Part" table="part">
<many-to-one name="container" column="container_id"
<property name="name" column="part_name" type="string" />
</union-subclass>
<union-subclass name="Container" table="container">
<set name="parts" inverse="true" cascade="all-delete-orphan">
<key column="container_id" />
<one-to-many class="Part" />
</set>
</union-subclass>
</class>

That is why I think it is a hibernate bug. Anyway your solution is approciated and it is working though the database schema looks not pretty.

ZJ


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 22, 2005 2:18 pm 
Regular
Regular

Joined: Thu Apr 14, 2005 2:15 pm
Posts: 66
ZJ,
this extra column is really necessary, until if you move the many-to-one to Part. So, the mapping table needs one column for the many-to-one reference and another column for the <set>. I
Suppose that you have this situation:

Container container1 = new Container();
Container container2 = new Container();
Part part1 = new Part();
part1.super.setContainer(container1);
container2.addPart(part1);

In this case, in the database record of part1, you will need one column to save the reference to container1 and another column to save the reference for container2.

Do you agree that it isn't a bug? Post again, If the doubt remain.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 22, 2005 3:19 pm 
Regular
Regular

Joined: Thu Apr 14, 2005 2:15 pm
Posts: 66
Suppose that the ID of container1 is 1 and container2 is 2.
You will have this register:

table PART
item_id: any
container_id_abstract: 1
part_name: any
container_id_set: 2

Do you understand now?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 22, 2005 3:22 pm 
Newbie

Joined: Mon Jun 20, 2005 12:20 pm
Posts: 17
Hi, Your code actually convice me that it is a bug. You break many-to-one association since part1.getContainer() will return container1 while the set returned by container1.getparts() will not include part1.

Chapter 22 (Example: Parent/Children) in Hibernate Reference 3.0 shows us the mapping:

<many-to-one name="parent" column="parent_id" not-null="true"/>

<set name="children" inverse="true">
<key column="parent_id"/>
<one-to-many class="Child"/>
</set>

and code:

Parent p = (Parent) session.load(Parent.class, pid);
Child c = new Child();
c.setParent(p);
p.getChildren().add(c);

or

public void addChild(Child c) {
c.setParent(this);
children.add(c);
}

Parent p = (Parent) session.load(Parent.class, pid);
Child c = new Child();
p.addChild(c);

You must set parent/chind relationship in a consistent way (My son calls me dad, and I list him as one of my children). Agree?

Regards,

ZJ


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 22, 2005 4:20 pm 
Regular
Regular

Joined: Thu Apr 14, 2005 2:15 pm
Posts: 66
ZJ,
now I understand what do you want. There is nothing wrong with my example, because in my example there isn't a business rule that indicate that part1 should be a child of container. I didn't thought in a bidirectional association.
But now, I understand that you want a bidirectional association. But your source doesn't represent this situation.
If you want a bidirectional association, you must change your code.

Container 1 -------------------- * Part

In this case, the Container class should have a set of Parts, as you done. But, the Part should have a reference to Container. The reference should be on Part and not on a superclass, because you want a bidirectional association.
In you code, you must force the values too.
Code:
public void addPart(Part part){
    part.setContainer(this);
    parts.add(part);
}


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 22, 2005 4:29 pm 
Regular
Regular

Joined: Thu Apr 14, 2005 2:15 pm
Posts: 66
Quote:
However, I believe that the many-to-one association should be defined in the base class because:

1. projectDB is declared in the base class (bstractObjectDB),
2. the many-to-one association only needs to be defined once, and
3....

1. If you want this, you should create a set of AbstractObjectDB and not a set of AbstractPropertyDefinitionDB.
2. Yes, move the many-to-one to AbstractPropertyDefinitionDB. The many-to-one association only needs to be define once, until in this situation.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 22, 2005 5:14 pm 
Newbie

Joined: Mon Jun 20, 2005 12:20 pm
Posts: 17
My original problem is very confusing and that is why I created a simplified container-parts case.

You did point out a problem in my association:

1. many-to-one: AbstractObjectDB-->ProjectDB
2. one-to-many: ProjectDB--->AbstractPropertyDefinitionDB (subclass of AbstractObjectDB)

Therefore, it is not a real bidirectional association.

In summary, there are 2 solutions to my "partial bidirectional association":

1. move many-to-one to all concreate subclasses, or
2. use the extra column in AbstractPropertyDefinitionDB for ProjectDB to facilitate the one-to-many association.

Thank you very much for your help. You really deserve receiving some credit points. Please reply to this message so that I can rate it.

Regards,
ZJ


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 22, 2005 7:23 pm 
Regular
Regular

Joined: Thu Apr 14, 2005 2:15 pm
Posts: 66
Thank you ZJ,
did you understand that there isn't a bug on hibernate?
Another way is putting the set on the abstract class.
You already rated me.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 12 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:
cron
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.