remove duplicate rows from database with hibernate - java

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.

Related

How to map an auto increment field in hibernate?

Please have a look at the below XML code
<?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">
<!-- Generated Feb 17, 2015 10:01:43 PM by Hibernate Tools 4.3.1 -->
<hibernate-mapping>
<class name="model.main.Family" table="family" catalog="****" optimistic-lock="version">
<id name="idFamily" type="int">
<column name="idFamily" />
<generator class="assigned" />
</id>
<many-to-one name="employee" class="model.main.Employee" fetch="select">
<column name="idEmployee" not-null="true" />
</many-to-one>
<property name="firstName" type="string">
<column name="FirstName" length="45" />
</property>
<property name="middleName" type="string">
<column name="MiddleName" length="45" />
</property>
<property name="lastName" type="string">
<column name="LastName" length="45" />
</property>
<property name="dob" type="date">
<column name="DOB" length="10" />
</property>
<property name="passportNumber" type="string">
<column name="PassportNumber" length="45" not-null="true" />
</property>
<property name="dateLeft" type="date">
<column name="DateLeft" length="10" />
</property>
<property name="lastUpdated" type="timestamp">
<column name="LastUpdated" length="19" not-null="true" />
</property>
<set name="visas" table="visa" inverse="true" lazy="true" fetch="select">
<key>
<column name="idFamily" />
</key>
<one-to-many class="model.main.Visa" />
</set>
</class>
</hibernate-mapping>
It is the Hibernate mapping class of my database table Family. We create the database separately using MySQL Work bench and then generate the mapping classes. We auto generated the mapping files using netbeans as mentioned in "Generating Hibernate Mapping Files and Java Classes" section of netbeans tutorial.
Now we have a problem. That is, we changed the primary key (idFamily) of our table Family to an auto generated field inside MySQL. Now, how can we change the above hibernate code so it identifies the idFamily as an auto generated one?
The other question is, manually editing one mapping class without regenerating all the mappings via a tool can "break" the system? For an example, like messing up with relationships?
In Annotation It work for me as
#GeneratedValue(strategy= GenerationType.IDENTITY)
for you hope it works
<generated-value strategy="IDENTITY" />
You're looking for an identity column. That indicates that the column value is auto-generated as an identity for the row by the RDBMS.
<generator class="identity" />
See the these Hibernate docs for more information. According to it:
Identity
supports identity columns in DB2, MySQL, MS SQL Server, Sybase and HypersonicSQL. The returned identifier is of type long, short or int.
Just replace your generator class to increment it will treat it as autoincrement
<generator class="increment"/>
<?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>
<class name="com.tech.spring4.model.User" table="Customer">
<id name="id" type="long">
<column name="USERID" unique="true"/>
<generator class="increment"/>
</id>
<property name="username"><column name="username" length="30" not-null="true"></column></property>
<property name="email"><column name="email" length="100" not-null="true"></column></property>
<property name="address"><column name="address" length="100" not-null="true"></column></property>
</class>
</hibernate-mapping>

What is wrong with this code that saves value objects?

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.

Version of the parent object does not change when its child object's state changes

I am using Hibernate3
I have a simple one to many relationship(Parent object has as set of child objects)
if the child objects are added/removed, the version of the parent object is updated where as if the state of the child object is changed, the version of the parent is not getting updated.
Here is the mapping -
Category.hbm.xml
<?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 package="net.codejava.hibernate">
<class name="Category" table="CATEGORY">
<id name="id" column="CATEGORY_ID">
<generator class="native"/>
</id>
<property name="name" column="NAME" />
<version name="version" type="integer" column="version" unsaved-value="null" />
<set name="products" inverse="true" cascade="all-delete-orphan">
<key column="CATEGORY_ID" not-null="true" />
<one-to-many class="Product"/>
</set>
</class>
Product.hbm.xml
<?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 package="net.codejava.hibernate">
<class name="Product" table="PRODUCT">
<id name="id" column="PRODUCT_ID">
<generator class="native"/>
</id>
<version name="version" type="integer" column="version" unsaved-value="null" />
<property name="name" column="NAME" />
<property name="description" column="DESCRIPTION" />
<property name="price" column="PRICE" type="float" />
<many-to-one name="category" class="Category"
column="CATEGORY_ID" not-null="true"/>
</class>
When the Product changes, Product.version is updated properly but the Category.version remains the same.
I assume this is a cross cutting concern and there has to be a plausible solution for this. I did a lot of searching and could not find one. Please help me out
Yes, this is just a limitation of the way hibernate works, I'm afraid. The only solution is to change it on both sides when you need to make a change.
You could also refresh the parent, but bear in mind that that will hit the database.
It's probably a subjective opinion, but to me it seems logical this way. However, one common way of handling this is to have something like lastUpdated field on parent entity, which you would set each time before calling update on it. This can be done in #PrePersist and/or #PreUpdate, and it would ensure that entity version changes whenever you update it, regardless of what changes are made to it or its relations.

java.lang.ClassCastException: org.hibernate.type.StringType cannot be cast to org.hibernate.type.VersionType

I am developing a database connector in order to retrieve data from a Oracle database. I have used the Hibernate tool included as a plug-in in Eclipse for the generation of the Hibernate mapping files because I have a lot of classes and tables to map. However, when I run the application, I have just get the following Exception:
java.lang.ClassCastException: org.hibernate.type.StringType cannot be cast to org.hibernate.type.VersionType
at org.hibernate.tuple.PropertyFactory.buildVersionProperty(PropertyFactory.java:107)
at org.hibernate.tuple.entity.EntityMetamodel.<init>(EntityMetamodel.java:181)
at org.hibernate.persister.entity.AbstractEntityPersister.<init>(AbstractEntityPersister.java:485)
at org.hibernate.persister.entity.SingleTableEntityPersister.<init>(SingleTableEntityPersister.java:133)
at org.hibernate.persister.PersisterFactory.createClassPersister(PersisterFactory.java:84)
at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:286)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1845)
at eu.cartif.dwhconn.database.DBManager.checkDWHStatus(DBManager.java:57)
at eu.cartif.dwhconn.database.DBManager.main(DBManager.java:24)
I think the problem could be the type of the property of the hbm file:
<hibernate-mapping>
<class name="eu.cartif.dwhconn.database.Ifcactorrole" table="IFCACTORROLE">
<id name="role" type="string">
<column name="ROLE" length="50" />
<generator class="assigned" />
</id>
<property name="userdefinedrole" type="string">
<column name="USERDEFINEDROLE" />
</property>
<property name="description" type="string">
<column name="DESCRIPTION" length="3000" />
</property>
<set name="ifcpersons" table="IFCPERSON" inverse="true" lazy="true" fetch="select">
<key>
<column name="ROLES" length="50" />
</key>
<one-to-many class="eu.cartif.dwhconn.database.Ifcperson" />
</set>
<set name="ifcpersonandorganizations" table="IFCPERSONANDORGANIZATION" inverse="true" lazy="true" fetch="select">
<key>
<column name="ROLES" length="50" />
</key>
<one-to-many class="eu.cartif.dwhconn.database.Ifcpersonandorganization" />
</set>
</class>
</hibernate-mapping>
However, I am not sure about it and I would not like to change all the types in all the hbms if that is not the solution. Anyone could help me, please.
Thank you very much in advance,
May you have a nice day
In my case, I generated entity from DB and some entities column name has "version". Generator for this names add "#Version" annotation, but this column type is String - for #Version annotation unacceptable
This types of problem occurs
if there are column name as "version" of "VARCHAR" (string) type in any table, means in hibernate "property" becomes "version" and "type" becomes "string", like-
in .hbm.xml file
<version name="xyz" type="string">
<column name="xyz" length="30" not-null="true" />
</version>
if there are any missing getter or setter method for a particular attribute.
if there are mismatch between .hbm.xml file and POJO class file.
I have checked several times all the mapping classes. Finally, the problem came from a mapping class which had not the proper type for an attribute... :(
Thank you for your responses
Missing length field on
<property name="userdefinedrole" type="string">
<column name="USERDEFINEDROLE" />
</property>
I faced this problem with working on an ancient, hibernate3 software.
The solution is this: until hibernate3.5, StringType was a child class of NullableType.
In hibernate 3.6, this relation was ended.
Thus, StringType was convertable to a NullableType only until hibernate 3.5, from hibernate 3.6 it is not so any more.
The simplest solution is, now decades away from the future: switch back to hibernate 3.5.

Delete element from Set

I have 2 classes Tema(Homework) and Disciplina (course), where a Course has a Set of homeworks.
In Hibernate i have mapped this to a one-to-many associations like this:
<class name="model.Disciplina" table="devgar_scoala.discipline" >
<id name="id" >
<generator class="increment"/>
</id>
<set name="listaTeme" table="devgar_scoala.teme">
<key column="Discipline_id" not-null="true" ></key>
<one-to-many class="model.Tema" ></one-to-many>
</set>
</class>
<class name="model.Tema" table="devgar_scoala.teme" >
<id name="id">
<generator class="increment" />
</id>
<property name="titlu" type="string" />
<property name="cerinta" type="binary">
<column name="cerinta" sql-type="blob" />
</property>
</class>
The problem is that it will add (insert rows in the table 'Teme') but it won't delete any rows and i get no exceptions thrown.
Im using the merge() method.
Although your question is unclear (how do you save and delete?), I'd suggest you need to set cascade:
<set cascade="all-delete-orphan">
As a sidenote - avoid names in your native language.
According to your description, I understand that a Tema cannot exist without its Disciplina: if you remove a Tema from the collection, you want it to be deleted. To tell Hibernate to do this, you must use cascade="all-delete-orphan".
<set name="listaTeme" table="devgar_scoala.teme" cascade="all-delete-orphan">
<key column="Discipline_id" not-null="true" ></key>
<one-to-many class="model.Tema" ></one-to-many>
</set>
Refer to the online documentation.

Categories