I have the following pretty simple many-to-one relationship between Person and their parents/children (which also are instances of Person again).
Person.hbm.xml
<?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 04.05.2011 15:02:31 by Hibernate Tools 3.3.0.GA -->
<hibernate-mapping>
<class name="test.Person" table="PERSONS">
<id name="id" type="long" access="field">
<column name="PERSON_ID" />
<generator class="native" />
</id>
<bag name="children" table="PERSONS" lazy="false" inverse="true" cascade="all">
<key column="PERSON_ID" not-null="false"></key>
<one-to-many class="test.Person" />
</bag>
<many-to-one name="parent" column="PARENT_ID" not-null="false" />
</class>
</hibernate-mapping>
Now, the problem in my case is that I have instances of Person which do not have parents (e.g. orphans).
If I try to persist these objects, I get:
java.sql.SQLException: null, message
from server: "Column
'PARENT_ID' cannot be null"
If I set not-null="true" in the mapping file, I get:
org.hibernate.PropertyValueException:
not-null property references a null or
transient value: test.parent
What's the magic trick here?
Valmar, since you are getting a SQL Exception, probably your COLUMN 'PARENT_ID' have a not null constraint. Check your table DDL. What database are you using?
Related
I want to create relation between Definition (DEF) and Details (DET) table by foreign keys in Hibernate. In this case, one definition has multiple details.
Definition table has ID column as PK
Details table has ID column as PK and DEFINITION_ID as FK
When I connect these inside of hbm.xml I am getting an error such as;
ERROR
Caused by: org.hibernate.MappingException: Repeated column in mapping
for entity: com.ykb.hmn.cms.commission.datamodel.ICmsExemptRestrictDet
column: ID (should be mapped with insert="false" update="false")
DEFINITION HBM XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.ykb.hmn.cms.commission.datamodel.ICmsExemptRestrictDef"
table="CMS_EXEMPT_RESTRICT_DEF">
<tuplizer class="com.ykb.hmn.inf.core.datamodel.IntfEntityTuplizer"
entity-mode="pojo" />
<id name="oid" type="java.lang.Long">
<column name="ID" />
<generator class="sequence">
<param name="sequence">SEQ_CMS_EXEMPT_RESTRICT_DEF</param>
</generator>
</id>
.
.
.
<bag name="cmsExemptRestrictDetails" table="CMS_EXEMPT_RESTRICT_DET"
inverse="true" lazy="true" fetch="select">
<key>
<column name="DEFINITION_ID" not-null="true" />
</key>
<one-to-many
class="com.ykb.hmn.cms.commission.datamodel.ICmsExemptRestrictDet" />
</bag>
</class>
</hibernate-mapping>
DETAIL HBM XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.ykb.hmn.cms.commission.datamodel.ICmsExemptRestrictDet"
table="CMS_EXEMPT_RESTRICT_DET">
<tuplizer class="com.ykb.hmn.inf.core.datamodel.IntfEntityTuplizer"
entity-mode="pojo" />
<id name="oid" type="java.lang.Long">
<column name="ID" />
<generator class="sequence">
<param name="sequence">SEQ_CMS_EXEMPT_RESTRICT_DET</param>
</generator>
</id>
<many-to-one name="cmsExemptRestrictDefinition" class="com.ykb.hmn.cms.commission.datamodel.ICmsExemptRestrictDef" fetch="select">
<column name="ID" not-null="true" />
</many-to-one>
<property name="definitionId" type="java.lang.Long">
<column name="DEFINITION_ID" />
</property>
</class>
</hibernate-mapping>
First - Do I need to define both many to one and one to many relation in each hbm xmls?
Second - Do I need to rename column ID of Detail something like DETAIL_ID?
Thanks.
The property mapping Definition_id is incorrect. The foreign key should not be mapped. Remove it and change the column name in manytoone mapping to definition_id:
Change the detail hbm xml to:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.ykb.hmn.cms.commission.datamodel.ICmsExemptRestrictDet"
table="CMS_EXEMPT_RESTRICT_DET">
<tuplizer class="com.ykb.hmn.inf.core.datamodel.IntfEntityTuplizer"
entity-mode="pojo" />
<id name="oid" type="java.lang.Long">
<column name="ID" />
<generator class="sequence">
<param name="sequence">SEQ_CMS_EXEMPT_RESTRICT_DET</param>
</generator>
</id>
<many-to-one name="cmsExemptRestrictDefinition" class="com.ykb.hmn.cms.commission.datamodel.ICmsExemptRestrictDef" fetch="select">
<column name="DEFINITION_ID" not-null="true" />
</many-to-one>
</class>
</hibernate-mapping>
I have a Project that contains a Set of Columns that contains a Set of Tasks that contains a Set of TaskAssigness.
I'm trying to update a column title without having to load its set of tasks, but I get the following error :
[AssertionFailure] - an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)
org.hibernate.AssertionFailure: collection [com.example.tasks.Task.taskAssignees] was not processed by flush()
I have the following hbm.xml :
Project.hbm.xml :
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"classpath://org/hibernate/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.exemple.tasks.project.Project" table="P_TASKS_PROJECT">
<cache usage="read-write" />
<id name="rowId" column="rowId">
<generator class="native"/>
</id>
...
<set name="columns" table="P_TASK_PROJECT_COLUMN" inverse="true" cascade="all" sort="com.exemple.tasks.project.ColumnIndexComparator">
<cache usage="read-write" />
<key column="projectId" not-null="true" />
<one-to-many class="com.exemple.tasks.project.Column" />
</set>
</class>
</hibernate-mapping>
Column.hbm.xml :
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"classpath://org/hibernate/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.example.tasks.project.Column" table="P_TASK_PROJECT_COLUMN">
<cache usage="read-write" />
<id name="rowId" column="rowId">
<generator class="native"/>
</id>
...
<property name="title" />
<many-to-one name="project" class="com.example.tasks.project.Project">
<column name="projectId" not-null="false" />
</many-to-one>
<set name="tasks" table="P_TASKS_JOIN_COLUMNS">
<cache usage="read-write" />
<key column="columnId" not-null="true" />
<many-to-many column="taskId" class="com.example.tasks.Task" unique="false" />
</set>
</class>
</hibernate-mapping>
Task.hbm.xml :
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"classpath://org/hibernate/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.example.tasks.Task" table="P_TASK">
<cache usage="read-write" />
<id name="rowId" column="rowId">
<generator class="native"/>
</id>
...
<set name="taskAssignees" table="P_TASK_ASSIGNEE" cascade="all-delete-orphan">
<cache usage="read-write" />
<key column="taskId" not-null="true" />
<one-to-many class="com.example.tasks.TaskAssignee" />
</set>
</class>
</hibernate-mapping>
TaskAsignee.hbm.xml :
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"classpath://org/hibernate/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.example.tasks.TaskAssignee" table="P_TASK_ASSIGNEE">
<cache usage="read-write" />
<id name="rowId" column="rowId">
<generator class="native"/>
</id>
...
<many-to-one name="task" class="com.example.tasks.Task" insert="false" update="false">
<column name="taskId" not-null="true" />
</many-to-one>
</class>
</hibernate-mapping>
I'm trying to update the title of a column this way :
//Updating column title
Column column = project.getColumn(index); // return a column from the project. Project contains a SortedSet of Column
column.setTitle("NewTitle");
session.saveOrUpdate(project);
This works fine if the column does not contains any tasks.
If I try to update a column containing tasks I get the following error message:
[AssertionFailure] - an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)
org.hibernate.AssertionFailure: collection [com.example.tasks.Task.taskAssignees] was not processed by flush()
If i get tasks and tasks assigness before updating the project, I have no errors :
Set<Task> tasks = col.getTasks();
if (tasks != null) {
for (Task task : tasks) {
task.getTaskAssignees();
}
}
session.saveOrUpdate(project);
Is there a way to change my column title, then update the project without having to get tasks and task assignees ? Can I tell hibernate just to update the column and not try to go further.
I try to understand hibernate but it is very hard.
I have a problem now that i don't really understand. Its about the many-to-many relations in my mapping file. If I save an object it wont save the "many" in my DB but it wont save it. I think it is in my mapping but i don't see it.
It's about flight and staff on the plane. When I save the plane the staff members must be save with it. But that wont happen.
Here is my mapping of both:
The Flight 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">
<!-- Generated 28-sep-2012 11:49:37 by Hibernate Tools 3.2.1.GA -->
<hibernate-mapping>
<class name="model.Flight" table="flights" catalog="flyaway_db">
<id name="number" type="int">
<column name="FlightNumber" />
<generator class="assigned" />
</id>
<set name="staffs" table="flightstaff" cascade="save-update">
<key>
<column name="FlightNumber" not-null="true" />
</key>
<many-to-many class="model.Staff">
<column name="StaffNumber" length="5" not-null="true" />
</many-to-many>
</set>
</class>
</hibernate-mapping>
The staff 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">
<!-- Generated 28-sep-2012 11:49:37 by Hibernate Tools 3.2.1.GA -->
<hibernate-mapping>
<class name="model.Staff" table="staff" catalog="flyaway_db">
<id name="staffNumber" type="string">
<column name="StaffNumber" length="5" />
<generator class="assigned" />
</id>
<set name="flightses" table="flightstaff" cascade="save-update">
<key>
<column name="StaffNumber" length="5" not-null="true" />
</key>
<many-to-many class="model.Flight">
<column name="FlightNumber" not-null="true" />
</many-to-many>
</set>
</class>
</hibernate-mapping>
You forgot the inverse="true" on one side of the bidirectional relationship.
Sorry for all the question but it was the model that wasn't correct! and i think Pache answer also helped!
Thanks all
I have two database tables, User and PageComment. Using Hibernate, I'm trying to store a Set of PageComment objects in the User comment (comments made to that user), by using one-to-many relationship in the hbm XML files.
The problem is, I seem to be able to retrieve the set from a User object, but as soon as I try to access any of the objects stored within the set, or even access on of the methods included in the set class (i.e. size()), the JVM throws "org.hibernate.exception.GenericJDBCException: could not initialize a collection". I'm at a loss on this one.
HBM For User Table:
<?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">
<hibernate-mapping>
<class name="User" table="user">
<id name="username" column="Username" type="string">
<generator class="assigned"></generator>
</id>
<property name="password" column="Password" type="string"></property>
<property name="firstname" column="Firstname" type="string"></property>
<property name="surname" column="Surname" type="string"></property>
<property name="email" column="Email" type="string"></property>
<property name="admin" column="Admin" type="integer"></property>
<set name="commentsMadeTo" inverse="true">
<key column="userMadeTo"/>
<one-to-many class="PageComment"/>
</set>
</class>
</hibernate-mapping>
HBM For PageComment:
<?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">
<hibernate-mapping>
<class name="PageComment" table="PageComment">
<composite-id>
<key-property name="userMadeBy" column="UserMadeBy" type="string" />
<key-property name="userMadeTo" column="UserMadeTo" type="string" />
<key-property name="time" column="Time" type="integer" />
<generator class="assigned"></generator>
</composite-id>
<property name="commentText" column="CommentText" type="string"></property>
<many-to-one name="userMadeTo" column="Username" not-null="true" class="User" />
</class>
</hibernate-mapping>
I'm trying to test the mapping with this method:
Session session = sessionFactory.openSession();
User theUser = (User)session.createQuery("FROM User WHERE Username='Samat'").uniqueResult();
System.out.println("Trying to print out all comments made to 'Samat'");
Set<PageComment> theComments = theUser.getCommentsMadeTo();
for(PageComment p: theComments){
System.out.println(p.getAllData());
}
I spot that there are some problems in the relationship mapping
HBM For User Table:
<set name="commentsMadeTo" inverse="true">
<key column="XXXXXXXX"/>
<one-to-many class="PageComment"/>
</set>
HBM For PageComment:
<many-to-one name="userMadeTo" column="XXXXXXX" not-null="true" class="User" />
The value XXXXX represents the column name on the "many" side (i.e PageComment table in your case) that associates to its "One" side. It should have the same value in both mapping hbm.
Try to change the hbm for user table to:
<set name="commentsMadeTo" inverse="true">
<key column="Username"/>
<one-to-many class="PageComment"/>
</set>
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>