I have two tables - Student and Address. They have one to many relationship. Student entity is having collection of address entity. When i updating collection of address in student. Its not updating the data and giving this error. When i was updating the parent entity with child collection, its taking next to be incremented key which is not in the database. -
Exception in thread "main" org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:129)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:124)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:189)
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:59)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3079)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3521)
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:88)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:395)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:387)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:303)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:349)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1195)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:404)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
at com.HibernateExample.test.HibernateTest.main(HibernateTest.java:51)
Caused by: org.postgresql.util.PSQLException: ERROR: insert or update on table "address" violates foreign key constraint "student_fk"
Detail: Key (id)=(5) is not present in table "student".
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2476)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2189)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:300)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:428)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:354)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:169)
at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:136)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:186)
... 14 more
Student.java
public class Student {
public int id;
public String firstName;
public String lastName;
public int age;
public Set<Address> address = new HashSet<>(0);
public Set<Address> getAddress() {
return address;
}
public void setAddress(Set<Address> address) {
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Address.java
public class Address {
public int id;
public String streetName;
public String cityName;
public String stateName;
public String plotNo;
public Student student;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getStreetName() {
return streetName;
}
public void setStreetName(String streetName) {
this.streetName = streetName;
}
public String getCityName() {
return cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
public String getStateName() {
return stateName;
}
public void setStateName(String stateName) {
this.stateName = stateName;
}
public String getPlotNo() {
return plotNo;
}
public void setPlotNo(String plotNo) {
this.plotNo = plotNo;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
}
HibernateTest.java
public class HibernateTest {
public static void main(String[] args) {
Configuration configuration = new Configuration();
configuration.configure("hibernate-cfg.xml");
#SuppressWarnings("deprecation")
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
session.setFlushMode(FlushMode.COMMIT);
System.out.println(session.getFlushMode().name());
Transaction transaction = session.beginTransaction();
Student student = (Student) session.get(Student.class, 3);
Address address = new Address();
address.setStateName("Kerala");
address.setCityName("Old Delhi");
address.setStreetName("Uttaam Nagar");
address.setPlotNo("158A");
address.setStudent(student);
student.getAddress().add(address);
session.update(student);
transaction.commit();
session.close();
sessionFactory.close();
}
}
address.hbm.xml
<hibernate-mapping>
<class name="com.HibernateExample.entity.Address" table="address">
<meta attribute="class-description">
This class contains the address detail.
</meta>
<id name="id" type="int" column="id">
<generator class="increment" />
</id>
<property name="streetName" column="street_name" type="string"/>
<property name="cityName" column="city_name" type="string"/>
<property name="stateName" column="state_name" type="string"/>
<property name="plotNo" column="plot_no" type="string"/>
<many-to-one name="student" class="com.HibernateExample.entity.Student" >
<column name="student_id" not-null="true"></column>
</many-to-one>
</class>
</hibernate-mapping>
student.hbm.xml
<hibernate-mapping>
<class name="com.HibernateExample.entity.Student" table="student">
<meta attribute="class-description">
This class contains the student detail.
</meta>
<id name="id" type="int" column="id">
<generator class="increment" />
</id>
<property name="firstName" column="first_name" type="string" length="40" />
<property name="lastName" column="last_name" type="string" length="40" />
<property name="age" column="age" type="int"/>
<set name="address" cascade="all">
<key column="student_id"/>
<one-to-many class="com.HibernateExample.entity.Address"/>
</set>
</class>
</hibernate-mapping>
From the Session javadoc, Session.update() is specified to work with a detached entity instance. "If there is a persistent instance with the same identifier, an exception is thrown." Exactly which exception is not specified, and cascading might send it down a complex code path, which could result in this error.
The Student object you modify is not detached, but rather persistent, because you got it by loading from the Session and have not closed the Session or done anything else that would detach it. This means that all modifications to it are saved to the database automatically, with no need for any manual call on Session. This is specified in the class javadoc for Session, with the sentence "Changes to persistent instances are detected at flush time and also result in an SQL UPDATE."
Simply delete the line session.update(student);, and I think your code will start working, including saving the new address through the cascaded relationship when you commit the transaction.
It's been a while since I've worked with cascades so I'm not entirely certain, but you might also need to set cascade on the other side of the relationship.
The "student_id" is not associated with any of your primary keys. If "student_id" exists in both Student and Address tables then change this line in your student mapping file from "id" to "student_id":
<id name="id" type="int" column="student_id">
Double check your database table with a database table viewer/browser.
It seems you try to insert an ID that already exists in the database (5)
Related
What is the equivalent way of defining dynamic component in hibernate by annotations?
public abstract class CustomizableEntity {
private Map customProperties;
public Map getCustomProperties() {
if (customProperties == null)
customProperties = new HashMap();
return customProperties;
}
public void setCustomProperties(Map customProperties) {
this.customProperties = customProperties;
}
public Object getValueOfCustomField(String name) {
return getCustomProperties().get(name);
}
public void setValueOfCustomField(String name, Object value) {
getCustomProperties().put(name, value);
}
}
my entity:
public class Contact extends CustomizableEntity {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
hibernate xml:
<hibernate-mapping auto-import="true" default-access="property" default-cascade="none" default-lazy="true">
<class abstract="false" name="com.enterra.customfieldsdemo.domain.Contact" table="tbl_contact">
<id column="fld_id" name="id">
<generator class="native"/>
</id>
<property name="name" column="fld_name" type="string"/>
<dynamic-component insert="true" name="customProperties" optimistic-lock="true" unique="false" update="true">
</dynamic-component>
</class>
</hibernate-mapping>
I want to use a dynamic-component by HashMap to create entities at runtime.
What is the equivalent way of defining dynamic component in hibernate by annotations?
http://www.infoq.com/articles/hibernate-custom-fields
As per the document i read here it says :
Hibernate save method returns the generated id immediately, this is possible because primary object is saved as soon as save method is invoked.
But in my example below, i have fired the save method and then kept the thread on sleep for 1 minute.
Within this timespace when i check the database the person_o table doesnt show any data in it. why isnt it showing the age and name value in it immediately after save. though it appears after the commit is executed once sleep is over .
addperson.java:
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public class addperson {
public static void main(String as[])
{
//Activate Hibernate Software
Configuration cfg=new Configuration();
//make hibernate software locating and reading cfg file
cfg=cfg.configure("/hibernate.cfg.xml");
//create SessionFactory obj
SessionFactory factory=cfg.buildSessionFactory();
//create HB session obj
Session session=factory.openSession();
Transaction tx = session.beginTransaction();
try {
// Create a person
person person = new person();
person.setName("Luna");
person.setAge(33);
Integer key = (Integer) session.save(person);
System.out.println("Primary Key : " + key);
person.setId(key);
System.out.println("---going for sleep---");
Thread.sleep(60000);
// Create the address for the person
personaddress address = new personaddress();
address.setAddressLine1("Lunaris");
address.setCity("Twinkle");
address.setState("MA");
address.setZipCode(10308);
address.setPerson(person);
person.setAddress(address);
key = (Integer) session.save(address);
System.out.println("Primary Key again : " + key);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
}
person.java
import java.io.Serializable;
public class person implements Serializable {
private static final long serialVersionUID = -9127358545321739524L;
private int id;
private String name;
private int age;
private personaddress address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public personaddress getAddress() {
return address;
}
public void setAddress(personaddress address) {
this.address = address;
}
}
personaddress.java
import java.io.Serializable;
public class personaddress implements Serializable {
private static final long serialVersionUID = -9127358545321739523L;
private int id;
private String addressLine1;
private String city;
private String state;
private int zipCode;
private person person;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAddressLine1() {
return addressLine1;
}
public void setAddressLine1(String addressLine1) {
this.addressLine1 = addressLine1;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public int getZipCode() {
return zipCode;
}
public void setZipCode(int zipCode) {
this.zipCode = zipCode;
}
public person getPerson() {
return person;
}
public void setPerson(person person) {
this.person = person;
}
}
hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property name="hibernate.connection.url">jdbc:oracle:thin:#localhost:1521:xe</property>
<property name="hibernate.connection.username">system</property>
<property name="hibernate.connection.password">oracle123</property>
<property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
<property name="hibernate.hbm2ddl.auto">create</property>
<property name="show_sql">true</property>
<mapping resource="person.hbm.xml"/> <mapping resource="personaddress.hbm.xml"/>
</session-factory>
</hibernate-configuration>
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">
<hibernate-mapping >
<class name="person" table="persons_o">
<id name="id" column="P_ID" type="integer">
<generator class="increment" />
</id>
<property name="name" column="NAME" update="false"
type="string" />
<property name="age" column="AGE" type="integer" />
<one-to-one name="address" cascade="all"></one-to-one>
</class>
</hibernate-mapping>
personaddress.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">
<hibernate-mapping>
<class name="personaddress" table="address_o"
dynamic-insert="true" dynamic-update="true"
select-before-update="false">
<id name="id" column="A_ID" type="integer">
<generator class="increment" />
</id>
<property name="addressLine1" column="ADDRESS_LINE_1"
type="string" />
<property name="city" column="CITY" type="string" />
<property name="state" column="STATE" type="string" />
<property name="zipCode" column="ZIPCODE" type="integer" />
<!-- In One-to-one we cannot specify the foreign key column
that has to be filled up
<one-to-one name="person" class="PersonOTO_B" cascade="all"
constrained="true"> </one-to-one>
-->
<many-to-one name="person" column="P_ID" unique="true"
not-null="true" lazy="false" />
</class>
</hibernate-mapping>
My output is :
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Hibernate: select max(P_ID) from persons_o
Primary Key : 1
---going for sleep--- (i am checking my db at this point but no data found )
Hibernate: select max(A_ID) from address_o
Primary Key again : 1
Hibernate: insert into persons_o (NAME, AGE, P_ID) values (?, ?, ?)
Hibernate: insert into address_o (ADDRESS_LINE_1, CITY, STATE, ZIPCODE, P_ID, A_ID) values (?, ?, ?, ?, ?, ?)
Please correct my knowledge.
Thanks
Jayendra Bhatt
session.save(Object), sesson.saveOrUpdate(Object) and etc. method only converts any transient object into persistence object,
means object associates with current hibernate session(actually object associates with session functional queues e.g. insertion queue,
updation queue and etc. according to corresponding operation) and gets hibernate generated(provided by generator class) id
if it's a new object. it never means that object will be immediately mapped on database.
When current hibernate session flushes or hibernate transaction commits then only actual query runs to map object data
into the database.
I have three classes
Student.java
public class Student {
long id;
String name;
Address address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
Address.java
public class Address {
String houseNumber;
String addrLine1;
String addrLine2;
String phone;
public String getHouseNumber() {
return houseNumber;
}
public void setHouseNumber(String houseNumber) {
this.houseNumber = houseNumber;
}
public String getAddrLine1() {
return addrLine1;
}
public void setAddrLine1(String addrLine1) {
this.addrLine1 = addrLine1;
}
public String getAddrLine2() {
return addrLine2;
}
public void setAddrLine2(String addrLine2) {
this.addrLine2 = addrLine2;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
Hibernate Mapping for Student.hbm.xml
Student.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">
<hibernate-mapping>
<class name="Student" table="STUDENT">
<id name="id" type="long" column="ID"/>
<property name="name" column="NAME"/>
<component name="address" class="Address">
<property name="houseNumber" column="HOUSE_NUMBER" not-null="true"/>
<property name="addrLine1" column="ADDRLINE1"/>
<property name="addrLine2" column="ADDRLINE2"/>
<property name="phone" column="PHONE"/>
</component>
</component>
</class>
</hibernate-mapping>
Now I want to access the property houseNumber, phone using detached criteria
but when I try to get the property as address.phone
I get the errors as
org.hibernate.QueryException: could not resolve property: phone of: Student
The error occurs because Student really does not have the "phone", which is a Address property.
The correct usage should be something like session.createCriteria( Student.class ).add( Restrictions.eq( "address.phone", "myPhoneNumber" ) ).list() for common criterias.
The version with DetachedCriteria is
DetachedCriteria criteria = DetachedCriteria.forClass( Student.class ).add(Restrictions.eq( "address.phone", "99999999" ) );
List students = criteria.getExecutableCriteria( session ).list();
I have the following three classes:
public class Student {
private Integer studentId;
private StudentSchool studentSchool;
private School school;
public Integer getStudentId() {
return studentId;
}
public void setStudentId(Integer studentId) {
this.studentId = studentId;
}
public StudentSchool getStudentSchool() {
return studentSchool;
}
public School getSchool() {
return school;
}
public void setSchool(School school) {
this.school = school;
}
}
public class StudentSchool {
private Student student;
private School school;
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public School getSchool() {
return school;
}
public void setSchool(School school) {
this.school = school;
}
}
public class School {
private Integer schoolId;
private Set allStudents;
public Integer getSchoolId() {
return schoolId;
}
public void setSchoolId(Integer schoolId) {
this.schoolId = schoolId;
}
public Set getAllStudents() {
return allStudents;
}
public void setAllStudents(Set allStudents) {
this.allStudents = allStudents;
}
}
I have the following DDL:
create table Student (StudentId Integer);
create table StudentSchool (SchoolId Integer, StudentId Integer);
create table School (SchoolId Integer Primary Key);
I have the following HBM files:
School.hbm.xml
<hibernate-mapping>
<class name="School" table="School">
<property name="schoolId" type="integer" />
<set name="allStudents" table="StudentSchool" fetch="join">
<key column="schoolId" />
<composite-element class="StudentSchool">
<parent name="school"/>
<many-to-one name="student" column="studentId" not-null="true" class="Student" />
</composite-element>
</set>
</class>
</hibernate-mapping>
Student.hbm.xml
<hibernate-mapping>
<class name="Student" table="Student">
<property name="studentId" type="integer" />
<one-to-one name="studentSchool" class="StudentSchool" />
<!-- <one-to-one name="school" class="School" /> -->
</class>
</hibernate-mapping>
When I try to query the Student object based on the school, I get the following exception (even though I have a class called "StudentSchool" compiled in my classpath):
org.hibernate.MappingException: persistent class not known: StudentSchool
If I uncomment the one-to-one mapping to "School" and comment out the one-to-one mapping to "studentSchool", I get the following exception:
<AST>:1:143: unexpected AST node: : java.lang.NullPointerException
Does anyone have any ideas about what I did wrong with my hbm mapping? Thanks!
You should give the fully qualified name of your classes in the hbm files.
like somepackage.StudentSchool
EDIT: If all are in the same package, then try adding this
<hibernate-mapping>
<class name="Student" table="Student">
<property name="studentId" type="integer" />
<one-to-one name="studentSchool" class="StudentSchool" property-ref="student"/>
<!-- <one-to-one name="school" class="School" property-ref="student"/> -->
</class>
</hibernate-mapping>
This post is an continuation of this post
I have DlUser Class each object of this class may have DLFaceBook class and each object of DlFaceBook can have Friends which are mapped as myFriends.
I'm trying to map relation of the same class as many to many relation using bag mapping,composite primary key and static inner class. my code is the following:
public class DlUser{
public DlUser(){}
Long Id;
String FirstName;
String LastName;
....
DlFaceBook fbuser;
//// all requred
getters and setters...
}
The Facebook user class looks like this as you can see I have the collection of objectes with the class MyFriends:
public class DlFaceBook {
private long dlpId;
private String FbId;
private Collection<MyFriends> Friends;
public DlFaceBook(){}
public void setFbId(String FbId)
{
this.FbId = FbId;
}
public void setFriends(Collection<MyFriends> friends)
{
this.Friends = friends;
}
public Collection<MyFriends> getFriends()
{
return this.Friends;
}
public void setdlpId(long id)
{
this.dlpId = id;
}
public long getdlpId()
{
return this.dlpId;
}
public String getFbId()
{
return this.FbId;
}
}
MyFriends class looks like this:
public class MyFriends {
private MyFriendsId myFriendId;
private DlFaceBook me;
private DlFaceBook myFriend;
public MyFriendsId getmyFriendId(){
return this.myFriendId;
}
public void setmyFriendId(MyFriendsId fid){
this.myFriendId = fid;
}
public void setme(DlFaceBook me){
this.me = me;
}
public void setmyFriend(DlFaceBook friend){
this.myFriend = friend;
}
public DlFaceBook getme(){
return this.me ;
}
public DlFaceBook getmyFriend(){
return this.myFriend ;
}
public MyFriends(DlFaceBook me, DlFaceBook user){
this.me = me ;
this.myFriend = user;
this.myFriendId = new MyFriendsId(me.getdlpId(),user.getdlpId());
}
public static class MyFriendsId implements Serializable {
private long meId;
private long myFrId;
// getter's and setter's
public MyFriendsId() {}
public MyFriendsId(long meId, long myFriendId) {
this.meId = meId;
this.myFrId = myFriendId;
}
// getter's and setter's
public long getmeId(){
return this.meId;
}
public void setmeId(Integer id){
this.meId = id;
}
public long getmyFrId(){
return this.myFrId;
}
public void setmyFrId(long id){
this.myFrId = id;
}
}
}
Now the Mapping:
DlUser.hbm.xml is the following and it's simple:
<hibernate-mapping>
<class name="DlUser" table="Users">
<id name="Id" column="id" >
<generator class="sequence">
<param name="sequence">userseq</param>
</generator>
</id>
<property name="firstName">
<column name="FirstName" />
</property>
<property name="lastName">
<column name="LastName"/>
</property>
<many-to-one
name="FaceBook"
class="DlFaceBook"
cascade="all"
column="dlpId"
unique="true"
/>
</class>
</hibernate-mapping>
DlFacebook.hbm.xml looks like this:
<hibernate-mapping>
<class name="DlFaceBook" table="dlfacebook">
<id name="dlpId" type="java.lang.Long" column="dlpId">
<generator class="increment" />
</id>
<property name="fbId">
<column name="fbId" />
</property>
<bag name="Friends">
<key column="me_Id" />
<one-to-many class="MyFriends"/>
</bag>
</class>
</hibernate-mapping>
Then MyFriends.hbm.xml looks like this:
<hibernate-mapping>
<class name="MyFriends">
<composite-id name="myFriendId" class="MyFriends$MyFriendsId">
<key-property name="meId"/>
<key-property name="myFrId"/>
</composite-id>
<many-to-one name="me" class="DlFaceBook" insert="false" update="false"/>
<many-to-one name="myFriend" class="DlFaceBook" insert="false" update="false"/>
</class>
</hibernate-mapping>
When I'm executing my query I got the following error:
Hibernate: insert into dlfacebook (fbId, dlpId) values (?, ?)
Hibernate: insert into Users (FirstName, LastName, email, twitter, birthday, dlpId, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: update MyFriends set me_Id=? where meId=? and myFrId=?
Hibernate: update MyFriends set me_Id=? where meId=? and myFrId=?
Oct 2, 2010 1:21:18 PM org.hibernate.jdbc.BatchingBatcher doExecuteBatch
SEVERE: Exception executing batch:
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:85)
at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:70)
at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(BatchingBatcher.java:90)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:183)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)
at Test.main(Test.java:54)
Oct 2, 2010 1:21:18 PM org.hibernate.event.def.AbstractFlushingEventListener performExecutions
SEVERE: Could not synchronize database state with session
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:85)
at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:70)
at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(BatchingBatcher.java:90)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:183)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)
at Test.main(Test.java:54)
Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
I see that this error happens when we trying to update not existing row, but how can I make this code work?
Just Facebook and MyFriends
Facebook Notice add convenience method and MutableLong (later, i tell you why to use MutableLong)
public class Facebook {
private MutableLong id = new MutableLong();
public Long getId() { return id.longValue(); }
public void setId(Long id) { this.id.setValue(id); }
public MutableLong getIdAsMutableLong() {
return id;
}
private Collection<MyFriends> myFriends = new ArrayList<MyFriends>();
public Collection<MyFriends> getMyFriends() { return myFriends; }
public void setMyFriends(Collection<MyFriends> myFriends) { this.myFriends = myFriends; }
/**
* add convenience method
*/
public void addFriend(Facebook myFriendFacebook) {
myFriends.add(new MyFriends(this, myFriendFacebook));
}
}
MyFriends
public class MyFriends {
private MyFriendsId myFriendId;
public MyFriendsId getmyFriendId(){ return this.myFriendId; }
public void setmyFriendId(MyFriendsId myFriendId){ this.myFriendId = myFriendId; }
private Facebook me;
public Facebook getme() { return this.me; }
public void setme(Facebook me){ this.me = me; }
private Facebook myFriend;
public Facebook getmyFriend() { return this.myFriend; }
public void setmyFriend(Facebook friend) { this.myFriend = friend; }
public MyFriends() {}
public MyFriends(Facebook meFacebook, Facebook myFriendFacebook){
this.me = meFacebook ;
this.myFriend = myFriendFacebook;
this.myFriendId = new MyFriendsId(meFacebook.getIdAsMutableLong(), myFriendFacebook.getIdAsMutableLong());
}
public static class MyFriendsId implements Serializable {
private MutableLong meId = new MutableLong();
public Long getMeId() { return this.meId.longValue(); }
public void setMeId(Long id) { this.meId.setValue(id); }
private MutableLong myFriendId = new MutableLong();
public Long getMyFriendId(){ return this.myFriendId.longValue(); }
public void setMyFriendId(Long id) { this.myFriendId.setValue(id); }
public MyFriendsId() {}
public MyFriendsId(MutableLong meId, MutableLong myFriendId) {
this.meId = meId;
this.myFriendId = myFriendId;
}
#Override
public boolean equals(Object o) {
if (!(o instanceof MyFriendsId))
return false;
MyFriendsId other = (MyFriendsId) o;
return new EqualsBuilder()
.append(getMeId(), other.getMeId())
.append(getMyFriendId(), getMyFriendId())
.isEquals();
}
#Override
public int hashCode() {
return new HashCodeBuilder()
.append(getMeId())
.append(getMyFriendId())
.hashCode();
}
}
}
Mapping
<hibernate-mapping package="br.com._3845772.model.domain">
<class name="User">
<id name="id">
<generator class="native"/>
</id>
<many-to-one cascade="all" class="Facebook" name="facebook"/>
</class>
<class name="Facebook">
<id name="id">
<generator class="native"/>
</id>
<bag cascade="all" name="myFriends">
<key column="ME_FACEBOOK_ID" update="false"/>
<one-to-many class="MyFriends"/>
</bag>
</class>
<class name="MyFriends">
<composite-id class="MyFriends$MyFriendsId" name="myFriendId">
<key-property column="ME_FACEBOOK_ID" name="meId"/>
<key-property column="MY_FRIEND_FACEBOOK_ID" name="myFriendId"/>
</composite-id>
<many-to-one class="Facebook" column="ME_FACEBOOK_ID" insert="false" name="me" update="false"/>
<many-to-one class="Facebook" column="MY_FRIEND_FACEBOOK_ID" insert="false" name="myFriend" update="false"/>
</class>
</hibernate-mapping>
And this sample
Facebook meFacebook = new Facebook();
Facebook myFriendFacebook = new Facebook();
meFacebook.addFriend(myFriendFacebook);
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(myFriendFacebook);
session.save(meFacebook);
session.getTransaction().commit();
session.close();
Which gives me
Hibernate: insert into Facebook values ( )
Hibernate: insert into Facebook values ( )
Hibernate: select myfriends_.ME_FACEBOOK_ID, myfriends_.MY_FRIEND_FACEBOOK_ID from MyFriends myfriends_ where myfriends_.ME_FACEBOOK_ID=? and myfriends_.MY_FRIEND_FACEBOOK_ID=?
Hibernate: insert into MyFriends (ME_FACEBOOK_ID, MY_FRIEND_FACEBOOK_ID) values (?, ?)
A couple of notes
Hibernate does not support automatic generation of composite primary key. You must set up its value before saving
Your database must support the target generator strategy (If you does not know which generator strategy your database support, prefer to use a native strategy)
Each entity must supply a no-arg constructor
Now why MutableLong (encapsulated by a Long property) instead of Long ?
Number and its subclasses (Long is a Number) are immutable. So if you want Facebook.id (configured by database) and its counterpart MyFriend$MyFriendId.meId share the same value, you must use MutableLong. When the database set up Facebook.id, MyFriend$MyFriendId.meId automatically get its newest value. But it just occurs if you use a MutableLong.