Hibernate3: Self-Referencing Objects - java

Need some help on understanding how to do this; I'm going to be running recursive 'find' on a file system and I want to keep the information in a single DB table - with a self-referencing hierarchial structure:
This is my DB Table structure I want to populate.
DirObject Table:
id int NOT NULL,
name varchar(255) NOT NULL,
parentid int NOT NULL);
Here is the proposed Java Class I want to map (Fields only shown):
public DirObject {
int id;
String name;
DirObject parent;
...
For the 'root' directory was going to use parentid=0; real ids will start at 1, and ideally I want hibernate to autogenerate the ids.
Can somebody provide a suggested mapping file for this please; as a secondary question I thought about doing the Java Class like this instead:
public DirObject {
int id;
String name;
List<DirObject> subdirs;
Could I use the same data model for either of these two methods ? (With a different mapping file of course).
--- UPDATE: so I tried the mapping file suggested below (thanks!), repeated here for reference:
<hibernate-mapping>
<class name="my.proj.DirObject" table="category">
...
<set name="subDirs" lazy="true" inverse="true">
<key column="parentId"/>
<one-to-many class="my.proj.DirObject"/>
</set>
<many-to-one name="parent"
class="my.proj.DirObject"
column="parentId" cascade="all" />
</class>
...and altered my Java class to have BOTH 'parentid' and 'getSubDirs' [returning a 'HashSet'].
This appears to work - thanks, but this is the test code I used to drive this - I think I'm not doing something right here, because I thought Hibernate would take care of saving the subordinate objects in the Set without me having to do this explicitly ?
DirObject dirobject=new DirObject();
dirobject.setName("/files");
dirobject.setParent(dirobject);
DirObject d1, d2;
d1=new DirObject(); d1.setName("subdir1"); d1.setParent(dirobject);
d2=new DirObject(); d2.setName("subdir2"); d2.setParent(dirobject);
HashSet<DirObject> subdirs=new HashSet<DirObject>();
subdirs.add(d1);
subdirs.add(d2);
dirobject.setSubdirs(subdirs);
session.save(dirobject);
session.save(d1);
session.save(d2);

you can get the children from parent
<set name="subdirs" lazy="false" cascade="all-delete-orphan" inverse="true">
<key column="parentid " />
<one-to-many class="DirObject" />
</set>
parent from child
<many-to-one name="parent" class="DirObject">
<column name="parentid" />
</many-to-one>

I believe this will work ... completely untested.
<hibernate-mapping>
<class name="my.proj.DirObject" table="category">
...
<set name="subDirs" lazy="true" inverse="true">
<key column="parentId"/>
<one-to-many class="my.proj.DirObject"/>
</set>
<many-to-one name="parent"
class="my.proj.DirObject"
column="parentId" cascade="all" />
</class>
</hibernate-mapping>

You can actually have the following Java entity:
public DirObject {
int id;
String name;
DirObject parent;
List<DirObject> subdirs;
...
}
And map it on the DIROBJECT table:
ID int NOT NULL,
NAME varchar(255) NOT NULL,
PARENTID int NOT NULL);
Using the following mapping:
<?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="mypackage">
<class name="DirObject" table="DIROBJECT">
<id name="id" type="int">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="string">
<column name="NAME" length="150" not-null="true" unique="false" index="NAME" />
</property>
<bag name="subdirs" lazy="false" cascade="all-delete-orphan" inverse="true">
<key column="PARENTID" />
<one-to-many class="DirObject" />
</bag>
<many-to-one name="parent" class="DirObject">
<column name="PARENTID" />
</many-to-one>
</class>
</hibernate-mapping>

Related

Associate set mapping against not primary key column

I have two objets like:
public class Object1 implements Serializable {
protected Integer id; // This is the PK in the xml mapping
protected Integer otherId;
}
public class Object2 implements Serializable {
protected Integer id; // This is the PK in the xml mapping
protected Set<Object1> object1List; // I want to relate this set against the "otherId" attribute
}
And I have this hibernate XML mappings:
<class name="Object1" table="Object1Table">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="identity" />
</id>
<property name="otherId" type="java.lang.Integer">
<column name="other_id"></column>
</property>
</class>
<class name="Object2" table="Object2Table">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="identity" />
</id>
<set name="object1List" table="Object1Table" lazy="false" fetch="join" >
<key column="other_id" /> // This is not working
<one-to-many class="Object1" />
</set>
</class>
But I don't know how to relate the "set" mapping against the "other_id" attribute, it only works against the PK "id" of the "Object1" table.
Does anyone know how to solve this situation?
I think you need to mark the <set as inverse. Like crizzis mentioned, you'd be better off if you use the annotation model. A lot more people can help you with the annotation model. Apart from that, the HBM XML mapping will be replaced with the JPA orm.xml mapping at some point, so I wouldn't use that approach anymore.

Hibernate: Mapping with one-to-many on non-primary-key columns

I'm stuck at the hibernate xml mapping configuration.
I've established some tables with foreign key constraints in my MSSQL database:
Table ItemsBase
ID int primary-key
ItemID int unique index
... some more columns
Table Others
ID int primary-key
ItemID int unique index
... some more columns
The foreign key constraint is configured to connect these two tables by using the column "ItemID".
My ItemsBase.hbm.xml files looks like:
<hibernate-mapping>
<class name="de.delife.sql.ItemsBase" table="ItemsBase" schema="dbo" catalog="Delife_Plenty">
<id name="id" type="int">
<column name="ID" />
<generator class="assigned" />
</id>
<property name="itemId" type="java.lang.Integer">
<column name="ItemID" unique="true" />
</property>
<set name="otherses" table="Others" inverse="true" lazy="true" fetch="select">
<key property-ref="itemId">
<column name="ItemID" />
</key>
<one-to-many class="de.delife.sql.Others" not-found="ignore" />
</set>
</class>
</hibernate-mapping>
and the Others.hbm.xml files looks like:
<hibernate-mapping>
<class name="de.delife.sql.Others" table="Others" schema="dbo" catalog="Delife_Plenty">
<id name="id" type="int">
<column name="ID" />
<generator class="assigned" />
</id>
<many-to-one name="itemsBase" class="de.delife.sql.ItemsBase" fetch="select" property-ref="itemId">
<column name="ItemID" unique="true" />
</many-to-one>
</class>
</hibernate-mapping>
Everything looks fine for me, but when I run my program I get a hibernate error:
property [itemId] not found on entity [de.delife.sql.Others]
I have an established relation between ItemsBase and a table named ItemsProperties and it works, but with this "pretty" table "Others" I'm stuck.
I would be glad, if someone can help me on this matter. Thx in advance.
Try like this. I tried and its working for me.
<set name="otherses" table="Others" inverse="true" lazy="true" fetch="select">
<key column="itemId" foreign-key="itemId" property-ref="itemId"/>
<one-to-many class="de.delife.sql.Others" not-found="ignore" />
</set>
Item id should be defined as a property in Others.hbm.xml:
<property name="itemId" column="ItemId"/>

hibernate: how to create a composite foreign key in xml?

I have a class Event containing a composite primary key (start date and end date).
A EventPlanning class holds a Set of such Event objects and has to persist them using hibernate with XML.
I can do this for classes with a common primary key:
<!-- EventPlanning xml -->
....
<id name="id" column="id">
<generator class="native" />
</id>
<property name="name" column="name" type="string" update="false" />
<set name="events" table="events" cascade="all">
<key column="event_id"> // ###### here! ######
</key>
<one-to-many class="myPackage.Event" />
</set>
...
but I can't find out how this works with a composite key..
replacing the <key column="event_id"> with the following code doesn't work:
<key>
<property column="start_date" />
<property column="end_date" />
</key>
I'd be glad if somebody can show me the right syntax! :)
the Event xml looks like this:
<class name="myPackage.Even" table="events">
<composite-id>
<key-property name="startDate" column="start_date" type="date" />
<key-property name="endDate" column="end_date" type="date" />
</composite-id>
<property name="signinDeadline" column="signin_deadline"
type="date" />
<property name="confirmationDeadline" column="confirmation_deadline"
type="date" />
<set name="participants" table="participants" cascade="all">
<key column="event_id">
</key>
<one-to-many class="myPackage.Participants" />
</set>
</class>
thanks in advance! :)
Something like this works for me:
<class name="YourClass" table="your_table" ...>
<composite-id name="compositeId" class="DoubleDate">
<key-property name="start_date" column="start_date"/>
<key-property name="end_date" column="end_date"/>
</composite-id>
...
</class>
public class DoubleDate implements Serializable {
private Date start_date, end_date;
public DoubleDate() {
}
// setters, getters
}
public class YourClass {
private DoubleDate compositeId;
// public no args ctr, getters, setters, etc
}
After having now worked longer with JPA and Hibernate, I'd just say that you simply should not use composite primary keys. Caches use ids as keys that point to cached values, data retrieving methods like get and load expect the id as parameter etc.
The advantages gained by having an id field pay off against the additional space it needs.

Hibernate Problem Not Saving to database

I am getting a hibernate problem. I am trying with no success. I have a schema where there are Category,Attribute,AttributeOption. e.g. a category can be a 'computer', and its respective attribute can be 'RAM','Hard Disk' and e.g. 'RAM' can have attribute option '512MB','1024MB'
When I try the above schema with hibernate everything is OK.
Now I have one other requirement. A 'Category' can have many sub categories. e.g. a 'Computer' can have 'laptop' or 'Notebook' as sub categories. Now these subcategories are of the class Category themselves
then I get this scheme:
1. Category ------>Category
A category can contain many sub categories
e.g. A computer can be a notebook or laptop
2. Category ------>Attribure
A category can have many attribute
A notebook can have RAM , Hard Disk, Screen Size
3. Attribute ------>AttributeOption
An Attribute can have many attribute options
e.g. RAM can be 512 MB, 1024 MB
These are my classes without their getters and setters
Class Category:
public class Category implements IsSerializable
{
private long CategoryId;
private String CategoryName;
private Set <Category> SubCategory=new HashSet <Category> ();
private Set <Attribute> AllAttributes= new HashSet <Attribute>();
}
Category Mapping File:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Dec 16, 2010 8:07:32 AM by Hibernate Tools 3.4.0.Beta1 -->
<hibernate-mapping>
<class name="com.BiddingSystem.Models.Category" table="CATEGORY">
<id name="CategoryId" type="long">
<column name="CATEGORYID" />
<generator class="native" />
</id>
<property name="CategoryName" type="java.lang.String">
<column name="CATEGORYNAME" />
</property>
<many-to-one name="ParentCategory" class="com.BiddingSystem.Models.Category">
<column name="PARENTCATEGORYID" />
</many-to-one>
<set name="SubCategory" inverse="true" lazy="true" cascade="all" fetch="join">
<key>
<column name="PARENTCATEGORYID" />
</key>
<one-to-many class="com.BiddingSystem.Models.Category" />
</set>
<set name="AllAttributes" table="ATTRIBUTE" inverse="false" lazy="true">
<key>
<column name="CATEGORYID" />
</key>
<one-to-many class="com.BiddingSystem.Models.Attribute" />
</set>
</class>
</hibernate-mapping>
Class Attribute:
public class Attribute
{
private long AttributeId;
private String AttributeName;
private Set <AttributeOption> Options= new HashSet <AttributeOption>();
}
Attribute Mapping File:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Dec 16, 2010 5:25:09 AM by Hibernate Tools 3.4.0.Beta1 -->
<hibernate-mapping>
<class name="com.BiddingSystem.Models.Attribute" table="ATTRIBUTE">
<id name="AttributeId" type="long">
<column name="ATTRIBUTEID" />
<generator class="native" />
</id>
<property name="AttributeName" type="java.lang.String">
<column name="ATTRIBUTENAME" />
</property>
<set name="Options" table="ATTRIBUTEOPTION" inverse="false" cascade="all">
<key>
<column name="ATTRIBUTEID" />
</key>
<one-to-many class="com.BiddingSystem.Models.AttributeOption" />
</set>
</class>
</hibernate-mapping>
Class AttributeOption:
public class AttributeOption
{
private long AttributeOptionId;
private String Option;
private String SQLValue;
}
Attribute Mapping File:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Dec 16, 2010 5:25:09 AM by Hibernate Tools 3.4.0.Beta1 -->
<hibernate-mapping>
<class name="com.BiddingSystem.Models.AttributeOption" table="ATTRIBUTEOPTION">
<id name="AttributeOptionId" type="long">
<column name="ATTRIBUTEOPTIONID" />
<generator class="native" />
</id>
<property name="Option" type="java.lang.String">
<column name="OPTION" />
</property>
<property name="SQLValue" type="java.lang.String">
<column name="SQLVALUE" />
</property>
</class>
</hibernate-mapping>
I am trying the following. I am not getting any error but It is not saving the 'Laptop' which is a category of 'computer' else everything is being saved. So i think the problem is with this part from the category mapping file:
<set name="SubCategory" table="CATEGORY" cascade="all">
<key>
<column name="CATEGORYID" />
</key>
<one-to-many class="com.BiddingSystem.Models.Category" />
</set>
This is part of my program
Category C=new Category();
C.setCategoryName("Computer");
AttributeOption R512= new AttributeOption();R512.setOption("512");R512.setSQLValue("512");
AttributeOption R1024= new AttributeOption();R1024.setOption("1024");R1024.setSQLValue("1024");
Category C0= new Category();
C0.setCategoryName("Laptop");
C.getSubCategory().add(C0);
Attribute RAM= new Attribute();
RAM.setAttributeName("RAM");
RAM.getOptions().add(R512);RAM.getOptions().add(R1024);
C.getAllAttributes().add(RAM);
Transaction tx = null;
try
{
tx=session.beginTransaction();
tx.begin();
session.saveOrUpdate(C);
tx.commit();
return true;
}
catch (Exception e)
{
tx.rollback();
e.printStackTrace();
return false;
}
Something seems wrong with this:
C0.getSubCategory().add(C0);
Shouldn't it be:
C.getSubCategory().add(C0);
Hummm, I see some place for improvement in this code :
First, you should use the persist() method to persist your entities.
Second, to persist a whole object graph, you must either a) persist the sub-objects manually, then the "main" object ; or b) use the Cascade parameter on your relationships so that persisting the "main" object also triggers the persistence of the related sub-objects.
You can find more info on cascading here :
http://docs.jboss.org/hibernate/stable/core/reference/en/html/example-parentchild.html#example-parentchild-cascades
Ok, I made it to work
The key to it is the category mapping file:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Dec 16, 2010 8:37:02 AM by Hibernate Tools 3.4.0.Beta1 -->
<hibernate-mapping>
<class name="com.BiddingSystem.Models.Category" table="CATEGORY">
<id name="CategoryId" type="long">
<column name="CATEGORYID" />
<generator class="native" />
</id>
<property name="CategoryName" type="java.lang.String">
<column name="CATEGORYNAME" />
</property>
<many-to-one name="ParentCategory" class="com.BiddingSystem.Models.Category">
<column name="PARENT_CATEGORY_ID" />
</many-to-one>
<set name="SubCategory" lazy="false" cascade="all-delete-orphan" inverse="true">
<key>
<column name="PARENT_CATEGORY_ID" />
</key>
<one-to-many class="com.BiddingSystem.Models.Category" />
</set>
<set name="AllAttributes" table="ATTRIBUTE" inverse="false" lazy="true">
<key>
<column name="CATEGORYID" />
</key>
<one-to-many class="com.BiddingSystem.Models.Attribute" />
</set>
</class>
</hibernate-mapping>

Hibernate Bi-Directional List Association

I'm sure there must be thousands of examples demonstrating this association but I can't seem to find one anywhere.
I have a one-many relationship from Parent-Child and a many-one relationship from Child-Parent:
class Parent {
private Long id;
private String name;
private List<Child> children;
}
class Child {
private Long id;
private String name;
private Parent parent;
}
I'm expecting to end up with 2 tables that look as follows:
Parent
- id : bigint
- name : varchar
Child
- id : bigint
- parent_id : bigint
- sequence : bigint
- name : varchar
Have I got the right idea? If so does anyone know what I need to put in my mapping file so that when a parent is deleted so too are it's children.
Thanks in advance.
James
Found the solution in the end although I don't understand why I need insert="false" and update="false":
<hibernate-mapping>
<class name="foo.Parent" table="Parent">
<id name="id" type="int" column="id">
<generator class="native" />
</id>
<property name="name" type="java.lang.String" column="name" length="50" />
<list name="children" cascade="all">
<key column="parent_id" />
<index column="sequence" />
<one-to-many class="foo.Child" />
</list>
</class>
<class name="foo.Child" table="Child">
<id name="id" type="int" column="id">
<generator class="native" />
</id>
<property name="name" type="java.lang.String" column="name" length="50" />
<many-to-one name="parent" class="foo.Parent" column="parent_id" insert="false" update="false" />
</class>
</hibernate-mapping>

Categories

Resources