I have two entities and two value objects - Employee, Card, Employee Number & Card Number. The relationship between Employee and Card is a one-to-many. I create an instance of Employee and an instance of Card like so and save them to the database...
EmployeeRepositoryHibernate employeeRepository = new EmployeeRepositoryHibernate();
employeeRepository.setSessionFactory();
employeeRepository.getSession().beginTransaction();
EmployeeNumber employeeNumber = new EmployeeNumber("MNO");
Location location = new Location("Room 1");
CardNumber cardNumber = new CardNumber("1");
Employee employee = new Employee(employeeNumber, location);
Card card = new Card(cardNumber, "1111", employee);
employeeRepository.getSession().save(employee);
employeeRepository.getSession().save(card);
employeeRepository.getSession().getTransaction().commit();
employeeRepository.getSession().close();
Except, it won't save, the following error message is shown... I can save an employee, but the message is thrown when I try to save a related card... the mysql database isn't relational yet.. both tables are separate...
Problem fixed: required related tables.
Caused by: java.sql.SQLException: Field 'employeeNumber' doesn't have a default value
Here are the two Hibernate XML mapping files for Card and Employee...
Card
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping default-access="field">
<class name="model.Card" table="Card">
<id name="CardID" type="long">
<column name="CardID" />
<generator class="identity" />
</id>
<component name="cardNumber" unique="true">
<property name="number" column="cardNumber"/>
</component>
<many-to-one name="employee" class="model.Employee" fetch="select">
<column name="EmpID" not-null="true"></column>
</many-to-one>
<property name="PIN" column="PIN"/>
</class>
</hibernate-mapping>
Employee
<?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 default-access="field">
<class name="model.Employee" table="employee">
<id name="EmpID" column="EmpID">
<generator class="org.hibernate.id.IdentityGenerator"/>
</id>
<component name="employeeNumber" class="model.EmployeeNumber" >
<property name="number" column="employeeNumber" type="string"/>
</component>
<component name="location">
<property name="location" column="Location" type="string"/>
</component>
<set name="cards" inverse="true" cascade="all">
<key>
<column name="EmpID" not-null="true"></column>
</key>
<one-to-many class="model.Card"/>
</set>
</class>
</hibernate-mapping>
One of these might help:
Add a default value to the column employeeNumber
ALTER TABLE 'table_name' ALTER 'employeeNumber' SET DEFAULT NULL
Use auto increment if you are using employeeNumber as a primary key.
Supply value to the employeeNumber column during insertion.
Related
Its being a while since I don't do Hibernate and I wanted to do some simple example the other day but when I needed to do a one to many relationship the many side doesn't get inserted into the database. This is how the database looked like.
This are my mappings for the person:
Java
public class ORMPerson implements Serializable {
private Long uniqueId;
private String firstName;
private String secondName;
private Long fkAddress;
hbm
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="orm">
<class name="orm.ORMPerson" table="PERSON">
<id name="uniqueId" column="UNIQUE_ID">
<generator class="increment"/>
</id>
<property name="firstName" column="FIRST_NAME"/>
<property name="secondName" column="SECOND_NAME"/>
<many-to-one name="fkAddress" class="orm.ORMPerson" column="FK_ADDRESS" cascade="all" not-null="false" />
</class>
</hibernate-mapping>
This are the mappings for Address:
Java
public class ORMAddress implements Serializable {
private Long uniqueId;
private String firstLine;
private String secondLine;
private String postcode;
private Set<ORMPerson> ormPersons;
hbm
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="orm">
<class name="orm.ORMAddress" table="ADDRESS">
<id name="uniqueId" column="UNIQUE_ID">
<generator class="increment"/>
</id>
<property name="firstLine" column="FIRST_LINE"/>
<property name="secondLine" column="SECOND_LINE"/>
<property name="postcode" column="POSTCODE"/>
<set name="ormPersons" table="ADDRESS" inverse="true" fetch="select" cascade="save-update">
<key>
<column name="UNIQUE_ID" not-null="true" />
</key>
<one-to-many class="ORMPerson"/>
</set>
</class>
</hibernate-mapping>
And this is the client code that I use to insert an address with multiple persons:
ORMAddress ormAddress = new ORMAddress();
ormAddress.setFirstLine(address.getFirstLine());
ormAddress.setSecondLine(address.getSecondLine());
ormAddress.setPostcode(address.getPostcode());
ormAddress.setOrmPersons(ormPersons);
session.save(ormAddress);
session.getTransaction().commit();
If I try to call the session.save() method with ormPersons, I will see the data being added to the database, but the foreign kew will have no value. I think this is because I just have a not-null="false" in Person but this is not a solution, I think all should be inserted automatically by just calling once the save method.
The reason is hidden in the inverse="true" mapping. This is saying to Hibernate:
when you persist collection - let that job on its items. These items must be aware of their parent.
But as we can see above, the ormPersons are not provided with back reference to ormAddress.
...
// after that line we have to do more
ormAddress.setOrmPersons(ormPersons);
// we have to assign back reference
for(ORMPerson ormPerson: ormPersons) {
ormPerson.setOrmAddress(ormAddress);
}
and also we would need ORMAddress reference inside of the ORMPerson - not as LONG
public class ORMPerson implements Serializable {
...
private ORMAddress ormAddress;
hbm
<class name="orm.ORMPerson" table="PERSON">
....
<many-to-one name="ormAddress" class="orm.ORMPerson"
column="FK_ADDRESS" cascade="all" not-null="false" />
</class>
And finally, many-to-one and one-to-many must use the same column
hbm of Address (FK_ADDRESS):
<class name="orm.ORMAddress" table="ADDRESS">
...
<set name="ormPersons" table="ADDRESS" inverse="true"
fetch="select" cascade="save-update">
<key>
//<column name="UNIQUE_ID" not-null="true" />
<column name="FK_ADDRESS" not-null="true" /> // the parent id
</key>
<one-to-many class="ORMPerson"/>
</set>
Check the doc for an example:
23.2. Bidirectional one-to-many
I'm trying to do many-to-many mapping, but have a problem with a code below. Tables created with this code looks fine, foreign keys are added properly. The problem occurs when I'm trying to create related objects and save them to db. After lunching app I have one row in table KURS, one row in table KATEGORIE, but the third table - KURSY_KATEGORIE is empty :(
Table1:
<?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 2012-11-08 11:48:42 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="model.Kurs" table="KURS" node="kurs">
<id name="id" type="long">
<column name="ID_KURSU" />
<generator class="native" />
</id>
...
<set cascade="save-update" name="kategorie" inverse="true" lazy="true" table="KURSY_KATEGORIE">
<key foreign-key="FK_KATEGORIE_KURSY">
<column name="ID_KURSU" />
</key>
<many-to-many class="model.Kategoria" column="ID_KATEGORI"/>
</set>
</class>
</hibernate-mapping>
Table2:
<?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 2012-11-08 11:48:42 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="model.Kategoria" table="KATEGORIA" node="kategoria">
<id name="id" type="long">
<column name="ID_KATEGORI" />
<generator class="native" />
</id>
...
<set cascade="save-update" name="kursy" table="KURSY_KATEGORIE" inverse="true" lazy="true">
<key foreign-key="FK_KURSY_KATEGORIE">
<column name="ID_KATEGORI" />
</key>
<many-to-many class="model.Kurs" column="ID_KURSU"/>
</set>
</class>
</hibernate-mapping>
And .java file:
Session session = SESSION_FACTORY.openSession();
Transaction tx = session.beginTransaction();
GregorianCalendar Data_rozp = new GregorianCalendar();
Kategoria cat1 = new Kategoria("Kategoria1");
Set<Kategoria> kategorie = new HashSet<Kategoria>(3);
kategorie.add(cat1);
Kurs k1 = new Kurs(Data_rozp, "kurs1", 100);
Set<Kurs> kursy = new HashSet<Kurs>(1);
kursy.add(k1);
cat1.setKursy(kursy);
k1.setKategorie(kategorie);
session.save(cat1);
session.save(k1);
tx.commit();
session.close();
Try changing:
<set cascade="save-update" name="kursy" table="KURSY_KATEGORIE" inverse="true" lazy="true">
To:
<set cascade="save-update" name="kursy" table="KURSY_KATEGORIE" lazy="true">
And:
<set cascade="save-update" name="kategorie" inverse="true" lazy="true" table="KURSY_KATEGORIE">
To:
<set name="kategorie" inverse="true" lazy="true" table="KURSY_KATEGORIE">
I'm surprised that hibernate does not throw an exception for invalid configuration (both ends can't be set as inverse - one must be the owner)
I have an hbm file which is as below:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping auto-import="true" default-lazy="false">
<class name="com.saman.entity.hibernate.EmployeeEntity"
table="Employee" optimistic-lock="version">
<id name="id">
<column name="Id" sql-type="bigint"/>
<generator class="native"/>
</id>
<timestamp name="version" source="db"/>
<property name="firstName">
<column name="FirstName" sql-type="nvarchar(300)"/>
</property>
<property name="lastName">
<column name="LastName" sql-type="nvarchar(300)"/>
</property>
<property name="employeeType">
<column name="EmployeeType" sql-type="nvarchar(300)"/>
</property>
<set name="shifts" table="Shifts" inverse="true" lazy="true" fetch="select">
<key>
<column name="Id" not-null="true"/>
</key>
<one-to-many class="com.saman.entity.hibernate.ShiftEntity"/>
</set>
</class>
</hibernate-mapping>
now I wanted if I add an employee and persist it, if then I add another employee with the previous information, my system raises an exception and tell me that I have another employee in the database with that informations.
does hibernate give me this option?
Well just add this to your mapping
<properties name="firstName_lastName_unique" unique="true">
<property name="firstName"/>
<property name="lastName"/>
</properties>
I think I understand what you want to achieve. But I don't know if you search your problem in stackoverflow first. This might be your answer How to do multiple column UniqueConstraint in hbm?
Have you set an auto increment on the ID column in your database?
You already have a generator for the id value. This should generate a unique id, but it only does so if these two conditions are true:
The column either is defined as autoincrement (p. ex. MySQL) or has a sequence (p. ex. Oracle)
When saving a new row, the member variable id is set to 0.
I can imagine, when you save a new value with previous information, the variable id still has a value != 0, and in this case the database uses the given value instead of generating a new unique one, which will fail due to the unique constraint.
This error also can appear if there is a second unique index on the table.
I am doing a proof of concept for one to many mapping with no success. My schema is as follows:
Student ---->Phone
class Student
public class Student implements java.io.Serializable
{
private Set<Phone> studentPhoneNumbers = new HashSet<Phone>();
// other setters and getters and constructors
}
class Phone
public class Phone implements java.io.Serializable
{
private Student student;
// other setters and getters and constructors
}
Student 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 5, 2010 7:56:05 PM by Hibernate Tools 3.4.0.Beta1 -->
<hibernate-mapping>
<class name="com.BiddingSystem.domain.Student" table="STUDENT">
<id name="studentId" type="long">
<column name="STUDENTID" />
<generator class="native" />
</id>
<property name="studentName" type="java.lang.String">
<column name="STUDENTNAME" />
</property>
<set name="studentPhoneNumbers" table="PHONE" inverse="true" cascade="all">
<key>
<column name="STUDENTID" not-null="true" />
</key>
<one-to-many class="com.BiddingSystem.domain.Phone" />
</set>
</class>
</hibernate-mapping>
Phone 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 5, 2010 7:56:05 PM by Hibernate Tools 3.4.0.Beta1 -->
<hibernate-mapping>
<class name="com.BiddingSystem.domain.Phone" table="PHONE">
<id name="phoneId" type="long">
<column name="PHONEID" />
<generator class="native" />
</id>
<property name="phoneType" type="java.lang.String">
<column name="PHONETYPE" />
</property>
<property name="phoneNumber" type="java.lang.String">
<column name="PHONENUMBER" />
</property>
<many-to-one name="student" class="com.BiddingSystem.domain.Student" not-null="true">
<column name="STUDENTID" not-null="true"/>
</many-to-one>
</class>
</hibernate-mapping>
But when I am doing this:
Session session = gileadHibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
Set<Phone> phoneNumbers = new HashSet<Phone>();
phoneNumbers.add(new Phone("house","32354353"));
phoneNumbers.add(new Phone("mobile","9889343423"));
Student student = new Student("Eswar", phoneNumbers);
session.save(student);
transaction.commit();
session.close();
I am getting the following errors:
Caused by: org.hibernate.PropertyValueException: not-null property references a null or transient value: com.BiddingSystem.domain.Phone.student
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:101)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:313)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:144)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:117)
at
org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:677)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:669)
at org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.java:252)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:392)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:335)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:425)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:362)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:338)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
at org.hibernate.engine.Cascade.cascade(Cascade.java:161)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:476)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:354)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:144)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:705)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:693)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:689)
at com.BiddingSystem.server.GreetingServiceImpl.greetServer(GreetingServiceImpl.java:52)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at net.sf.gilead.gwt.PersistentRemoteService.processCall(PersistentRemoteService.java:174)
... 21 more
Can someone help in setting the proper attributes for this
phone mapping xml file
<many-to-one name="student" class="com.BiddingSystem.domain.Student" not-null="true">
<column name="STUDENTID" not-null="true"/>
</many-to-one>
and Student mapping file
<set name="studentPhoneNumbers" table="PHONE" inverse="true" cascade="all">
<key>
<column name="STUDENTID" not-null="true" />
</key>
<one-to-many class="com.BiddingSystem.domain.Phone" />
</set>
You need to push the Student object into the Phone objects:
foreach (Phone phone : student.getStudentPhoneNumbers()) {
phone.setStudent(student);
}
A more typical piece of code would create the Student instance first, and then add the phone numbers to it. I've often implemented a method to help with this, e.g. in Student.java:
public void addPhoneNumber(Phone phone) {
phone.setStudent(this);
getStudentPhoneNumbers().add(phone);
}
public void addPhoneNumber(String type, String number) {
addPhoneNumber(new Phone(type, number));
}
So now you can say student.addPhoneNumber("home", "12354") and it will simply DTRT.
Since you are using Bi-Direction association with inverse=true option, the child objects will be persisted independently. The parent object doesn't take care about synchronization with child objects. So in this case, there will one insert query for parent object and as many insert query as the child objects. So, child object need to have reference of parent object at insert time. Also you have defined not-null=true at parent as well as child side.
When we use inverse=false, parent will be saved first, then child will be saved without reference of parent object and at last the parent will update its relationship with child using the update queries.
Hope this helps.
1). Phone number must have a student so create a student object (stu = new Student()) first and
then call phone.setStudent(stu);
ex:
Set<Phone> phoneNumbers = new HashSet<Phone>();
Phone p1 = new Phone("house", "32354353");
phoneNumbers.add(p1);
Phone p2 = new Phone("mobile", "9889343423");
phoneNumbers.add(p2);
Student student = new Student("Eswar", phoneNumbers);
student.setPhones(phoneNumbers);
session.save(student); //Till now, This code is work if you use cascade = 'all' in //my_mapping_file.xml or
session.save(p1); session.save(p2); //call session.save on both phone objects
I have two tables: a "Module" table and a "StaffModule" table. I want to display a list of modules by which staff are present on the staffmodule mapping table.
I've tried
from Module join Staffmodule sm with ID = sm.MID
with no luck, I get the following error
Path Expected for join!
However, I thought I had the correct join too allow this, but this is obviously not the case. Can any one help?
StaffModule HBM
<?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">
<!-- Generated Apr 26, 2010 9:50:23 AM by Hibernate Tools 3.2.1.GA -->
<hibernate-mapping>
<class name="Hibernate.Staffmodule" schema="WALK" table="STAFFMODULE">
<composite-id class="Hibernate.StaffmoduleId" name="id">
<key-many-to-one name="mid" class="Hibernate.Module">
<column name="MID"/>
</key-many-to-one>
<key-property name="staffid" type="int">
<column name="STAFFID"/>
</key-property>
</composite-id>
</class>
</hibernate-mapping>
and Module.HBM
<?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">
<!-- Generated Apr 26, 2010 9:50:23 AM by Hibernate Tools 3.2.1.GA -->
<hibernate-mapping>
<class name="Hibernate.Module" schema="WALK" table="MODULE">
<id name="id" type="int">
<column name="ID"/>
<generator class="assigned"/>
</id>
<property name="modulename" type="string">
<column length="50" name="MODULENAME"/>
</property>
<property name="teacherid" type="int">
<column name="TEACHERID" not-null="true"/>
</property>
</class>