I have a class like this,
class SampleClass implements Serializable {
String name;
Serializable fieldName;
}
And another class like,
class AnotherClass implements Serializable {
SampleClass sampleClass;
}
where both class has their getter and setter methods.
In the main class, I'm getting the sampleClass variable from getter function, and trying to use the sampleClass objects. But when I'm using that, I encounter the error like, could not deserialize.
How to access the members of SampleClass, or shall we have field members of type Serializable ?
Thanks.
Edited:
I am using hibernate, which uses many to one relation between aemploye and aaddress tables.
I created the Hibernate configuration file, and Reverse engineering file in net beans, for the above two tables.
Then I generated the POJO class.
The class and xml are:
Aaddress.hbm.xml
<hibernate-mapping>
<class name="hibernatetutor.tablebeans.Aaddress" table="aaddress" schema="public">
<id name="sno" type="int">
<column name="sno" />
<generator class="assigned" />
</id>
<property name="street" type="serializable">
<column name="street" />
</property>
<set name="aemployes" inverse="true">
<key>
<column name="address" />
</key>
<one-to-many class="hibernatetutor.tablebeans.Aemploye" />
</set>
</class>
Aemploye.hbm.xml
<hibernate-mapping>
<class name="hibernatetutor.tablebeans.Aemploye" table="aemploye" schema="public">
<id name="id" type="int">
<column name="id" />
<generator class="assigned" />
</id>
<many-to-one name="aaddress" class="hibernatetutor.tablebeans.Aaddress" fetch="select">
<column name="address" />
</many-to-one>
<property name="name" type="string">
<column name="name" />
</property>
</class>
Aaddress.java
public class Aaddress implements java.io.Serializable {
private int sno;
private Serializable street;
private Set aemployes = new HashSet(0);
public int getSno() {
return this.sno;
}
public void setSno(int sno) {
this.sno = sno;
}
public Serializable getStreet() {
return this.street;
}
public void setStreet(Serializable street) {
this.street = street;
}
public Set getAemployes() {
return this.aemployes;
}
public void setAemployes(Set aemployes) {
this.aemployes = aemployes;
}
}
Aemploye.java
public class Aemploye implements java.io.Serializable {
private int id;
private Aaddress aaddress;
private String name;
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public Aaddress getAaddress() {
return this.aaddress;
}
public void setAaddress(Aaddress aaddress) {
this.aaddress = aaddress;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
Main.java
private void getData() {
Session session = HibernateUtils.getInstance().openSession();
Query query = session.createQuery("from Aemploye where id=:id");
query.setParameter("id", 1);
Aemploye a = (Aemploye) query.uniqueResult();
Aaddress a1 = a.getAaddress();
System.out.println(a1.getStreet());
}
The error is:
org.hibernate.type.SerializationException: could not deserialize
at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:217)
at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:240)
at org.hibernate.type.SerializableType.fromBytes(SerializableType.java:82)
at org.hibernate.type.SerializableType.get(SerializableType.java:39)
at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:163)
at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:154)
at org.hibernate.type.AbstractType.hydrate(AbstractType.java:81)
at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:2096)
at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1380)
at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1308)
at org.hibernate.loader.Loader.getRow(Loader.java:1206)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:580)
at org.hibernate.loader.Loader.doQuery(Loader.java:701)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
at org.hibernate.loader.Loader.loadEntity(Loader.java:1860)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:48)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:42)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3044)
at org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:395)
at org.hibernate.event.def.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:375)
at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:139)
at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:98)
at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:878)
at org.hibernate.impl.SessionImpl.immediateLoad(SessionImpl.java:836)
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:66)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111)
at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:150)
at hibernatetutor.tablebeans.Aaddress$$EnhancerByCGLIB$$44bec229.getStreet(<generated>)
at hibernatetutor.Main.getData(Main.java:33)
at hibernatetutor.Main.main(Main.java:24)
Caused by: java.io.StreamCorruptedException: invalid stream header
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:753)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:268)
at org.hibernate.util.SerializationHelper$CustomObjectInputStream.<init>(SerializationHelper.java:252)
at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:209)
... 29 more
On the basis of both the question, and some of the info from the comment section, I believe your troubles are caused by the following:
You have for some reason chosen the street attribute to be of type serializable. In your table this column has been defined as of type TEXT. Hibernate probably manages to save the serialized data to the column, but the database probably does not manage to keep them unaltered. Therefore, on retrieval, the now garbled serialized fail to deserialize.
The solution is, as Petr Pudlák noted, to get your mapping to be correct. If you choose a suitable binary type, such as BYTEA, then you will be able to store the binary data unaltered. The retrieval should then work.
This is not the right solution IMHO, which would be to choose a suitable data type in your java code in the first place. Having the type of street to be Serializable is confusing to anyone viewing your code. String would probably make more sense, and would also be a good fit for the column type TEXT.
Using a getter doesn't involve serialization unless you have some very unusual framework to do this.
I suggest you look at the exact stack trace (and post it in the question) and see where the exception is actually occurring.
I tried your classes, and it works for me:
import java.io.*;
class SampleClass implements Serializable {
String name;
Serializable fieldName;
}
class AnotherClass implements Serializable {
SampleClass sampleClass;
}
public class Ser {
public static void main(String argv[])
throws Exception
{
SampleClass s = new SampleClass();
s.name = "name";
s.fieldName = "fieldName";
AnotherClass a = new AnotherClass();
a.sampleClass = s;
// serialize the classes to a byte array
ByteArrayOutputStream os = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(a);
oos.close();
// deserialize the classes from the byte array
ObjectInputStream is
= new ObjectInputStream(
new ByteArrayInputStream( os.toByteArray() ));
a = (AnotherClass)is.readObject();
is.close();
// print something
System.out.println(a.sampleClass.name);
}
}
Can you post the exact code that causes the problem?
Related
I'm using spring hibernate for a web application. It has a OpenHours modal which return the open time. It has a field sundayOpen type="time". Whenever the time in database column 'sundayOpen' is equal to '00:00:00' the sundayOpen is returning null. But all the other times it returns the correct time.
I have experienced this issue with hibernate 5.4.2 and 3.6.0.
Is there any way to get '00:00:00' instead of null?
OpenHours.hbm.xml
<class name="com.example.OpenHours" table="openHours" schema="abxd_db">
<id name="id" type="long">
<column name="id"/>
<generator class="assigned"/>
</id>
<property name="sundayOpen" type="time">
<column length="16" name="sundayOpen"/>
</property>
</class>
OpenHours.java
public class OpenHours implements Serializable {
private long id;
private Time sundayOpen;
#Id
#Column(name = "id", nullable = false)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Time getSundayOpen() {
return sundayOpen;
}
public void setSundayOpen(Time sundayOpen) {
this.sundayOpen = sundayOpen;
}
}
You can create a custom UserType,
public class CustomTimeUserType implements UserType {
public void nullSafeSet(PreparedStatement ps, Object value, int index) throws HibernateException, SQLException {
if (value == null)
ps.setString(index, "00:00:00");
else
ps.setDate(index, (Time) value);
}
// implement other methods
}
And use it in property,
<property name="sundayOpen" type="time">
<column length="16" name="com.pkg.CustomTimeUserType"/>
</property>
I am not sure but you can also try with zeroDateTimeBehavior,
hibernate.connection.zeroDateTimeBehavior=round
Problem Solved. Thank you.
Now I have three tables movie_information, release_company and rating.
movie_information and rating are having one-to-one relationship while release_company and movie_information are having one-to-many relationship.
I am trying to build a CMS with hibernate but I found that I am not able to correctly construct the part that involve these three tables.
Here comes my code
MovieInformation.java
public class MovieInformation {
private ReleaseCompany releaseCompany;
private Rating rating;
// Other data member
// Constructor, getter and setter
public ReleaseCompany getReleaseCompany(){
ReleaseCompany newReleaseCompany = new ReleaseCompany(this.releaseCompany);
return newReleaseCompany;
}
public Rating getRating(){
Rating newRating = new Rating(this.rating);
return newRating;
}
public void setReleaseCompany(ReleaseCompany releaseCompany){
this.releaseCompany = new ReleaseCompany(releaseCompany);
}
}
ReleaseCompany.java
public class ReleaseCompany {
private int releaseCompanyId;
private String releaseCompanyName;
private Set<MovieInformation> movies = new HashSet<MovieInformation>();
public ReleaseCompany(){
}
public ReleaseCompany(String releaseCompanyName){
this.releaseCompanyName = releaseCompanyName;
}
public ReleaseCompany(ReleaseCompany releaseCompany){
this.releaseCompanyName = releaseCompany.getReleaseCompanyName();
}
public Set<MovieInformation> getMovies() {
Set<MovieInformation> newMoviesSet = new HashSet<MovieInformation>(movies);
return newMoviesSet;
}
public void setMovies(Set<MovieInformation> movies) {
this.movies = new HashSet<MovieInformation>(movies);
}
// Other constructor, getter and setter
}
Rating.java
public class Rating {
private MovieInformation movie;
// other data member
public void setMovie(MovieInformation movie){
this.movie = new MovieInformation(movie);
}
// other constructor, getter and setter
}
MovieInformation.hbm.xml
<class name="cart.hibernate.movieInformation.MovieInformation" table="movie_information">
<id column="move_id" name="movieId" type="long">
<generator class="native"/>
</id>
<one-to-one name="rating" class="cart.hibernate.rating.Rating" cascade="save-update"></one-to-one>
<many-to-one name="releaseCompany" class="cart.hibernate.releaseCompany.ReleaseCompany" unique="false"><!-- constrained="true" -->
<column name="release_company_id" not-null="true" />
</many-to-one>
// Other property
</class>
Rating.hbm.xml
<class name="cart.hibernate.rating.Rating" table="rating">
<id name="movieId" type="java.lang.Long">
<column name="movie_id" />
<generator class="foreign">
<param name="property">movie</param>
</generator>
</id>
<property column="avg_rate" name="avgRate" type="double"/>
<property column="num_of_rate" name="numOfRate" type="long"/>
<one-to-one name="movie" class="cart.hibernate.movieInformation.MovieInformation" constrained="true"></one-to-one>
</class>
ReleaseCompany.hbm.xml
<class name="cart.hibernate.releaseCompany.ReleaseCompany" table="release_company">
<id column="release_company_id" name="releaseCompanyId" type="int">
<generator class="native"/>
</id>
<property column="release_company_name" name="releaseCompanyName" type="string"/>
<set name="movies" table="movie_information" inverse="true" lazy="true" fetch="select">
<key>
<column name="movie_id" not-null="true" />
</key>
<one-to-many class="cart.hibernate.movieInformation.MovieInformation" />
</set>
</class>
Testing Main method
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = null;
tx = session.beginTransaction();
Rating rating = new Rating(5.6, 80);
ReleaseCompany releaseCompany = new ReleaseCompany();
releaseCompany.setReleaseCompanyName("a");
session.save(releaseCompany);
// ReleaseCompany releaseCompany = (ReleaseCompany)session.get(ReleaseCompany.class, 15);
// Another testing case that I have tried. It throw another exception,
// if you need the information in this part, please let me know.
MovieInformation movie = new MovieInformation("Matrix", 150, 1, 50, date, releaseDate, "good description");
movie.setRating(rating);
movie.setReleaseCompany(releaseCompany);
rating.setMovie(movie);
session.save(movie); // <--- Error occur here
tx.commit();
StackTrace
org.hibernate.PropertyValueException: not-null property references a null or transient value: cart.hibernate.movieInformation.MovieInformation.releaseCompany
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:100)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:312)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:203)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:129)
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:713)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:701)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:697)
at cart.hibernate.movieInformation.ManageMovieInformation.main(ManageMovieInformation.java:61)
BUILD SUCCESSFUL (total time: 1 second)
I have read several similar question, some of the people said the releaseCompany(in my case) object hasn't saved to the database so the setReleaseCompany() cannot work as expected. I am not sure whether the releaseCompany object exist or not because I cannot see the record in MySql(I am not sure whether the record would be saved or not if exceptions are thrown). Moreover, some of them said the attribute of the mapping tag is not correct but I am not sure whether mine are correct or not.
I apologies to put so much code in the post, hope that you could solve this problem.
Keep it simple :
public class MovieInformation {
private ReleaseCompany releaseCompany;
private Rating rating;
// Other data member
// Constructor, getter and setter
public ReleaseCompany getReleaseCompany(){
return releaseCompany;
}
public Rating getRating(){
return rating;
}
public void setReleaseCompany(ReleaseCompany releaseCompany){
this.releaseCompany = releaseCompany;
}
}
public class ReleaseCompany {
private int releaseCompanyId;
private String releaseCompanyName;
private Set<MovieInformation> movies = new HashSet<MovieInformation>();
public ReleaseCompany(){
}
public ReleaseCompany(String releaseCompanyName){
this.releaseCompanyName = releaseCompanyName;
}
public ReleaseCompany(ReleaseCompany releaseCompany){
this.releaseCompanyName = releaseCompany.getReleaseCompanyName();
}
public Set<MovieInformation> getMovies() {
return movies;
}
private void setMovies(Set<MovieInformation> movies) {
this.movies = movies;
}
// Other constructor, getter and setter
}
public class Rating {
private MovieInformation movie;
// other data member
public void setMovie(MovieInformation movie){
this.movie = movie;
}
// other constructor, getter and setter
}
Please note that setMovies(Set movies) is private, so the only way to change all movies is to do something like this:
releaseCompany.getMovies().clear();
releaseCompany.getMovies().addAll(newMovieCollection);
You need to that because:
hibernate need to track the changes made to the collection
hibernate put a proxy around the collection to do this tracking.
replacing the Set by another one implies that the hibernate proxy will be lost
I am facing problem of org.hibernate.PropertyValueException: not-null property references a null or transient value: com.master.model.AccountLoan.account.
There are two table Accout and AccountLoan, below is table structure for Account
Account--
create table ACCOUNT
(
ac_id INTEGER not null,
ac_name VARCHAR2(40) not null,
ac_islocked CHAR(1) not null
)
below is table structure for Account Loan
AccountLoan--
create table ACCOUNT_LOAN
(
al_id INTEGER not null,
al_ac_id INTEGER not null,
al_loanA NUMBER(15,2),
al_loanB NUMBER(15,2)
)
For both table data is comming from single jsp on single add button click. Add functionality is working fine.Account loan is optional, if user do not fill LoanA and LoanB field then no record is in account loan,if user fill LoanA and LoanB field then record is insert in account loan table.
Aim
I want update account record which have not account loan.When i am updating account record following exception is throwing--
org.hibernate.PropertyValueException: not-null property references a null or transient value: com.master.model.AccountLoan.account.
Below is Both model java file.
import java.math.BigDecimal;
public class Account extends BaseM
{
private String name;
private Boolean isLocked;
private AccountLoan accountLoan;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public Boolean getIsLocked()
{
return isLocked;
}
public void setIsLocked(Boolean isLocked)
{
this.isLocked = isLocked;
}
public AccountLoan getAccountLoan()
{
return accountLoan;
}
public void setAccountLoan(AccountLoan accountLoan)
{
this.accountLoan = accountLoan;
}
}
Account Loan model java file
import java.math.BigDecimal;
public class AccountLoan extends BaseM
{
private BigDecimal loanA;
private BigDecimal loanB;
private Account account;
public BigDecimal getloanA()
{
return loanA;
}
public void setloanA(BigDecimal loanA)
{
this.loanA= loanA;
}
public BigDecimal getloanB()
{
return loanB;
}
public void setLoanInterest(BigDecimal loanB)
{
this.loanB= loanB;
}
public Account getAccount()
{
return account;
}
public void setAccount(Account account)
{
this.account = account;
}
}
Account.hbm.xml
<hibernate-mapping>
<class name="com.master.model.Account" table="ACCOUNT" dynamic-update="true">
<id name="id" column="AC_ID" type="long">
<generator class="com.common.support.IdGenerator">
<param name="sequence">ACID_SEQ</param>
</generator>
</id>
<one-to-one name="accountLoan" class="com.master.model.AccountLoan" cascade="all"/>
<property name="name" column="AC_NAME" type="string" />
<property name="isLocked" column="AC_ISLOCKED" type="yes_no" />
</class>
</hibernate-mapping>
AccountLoan.hbm.xml
<hibernate-mapping>
<class name="com.master.model.AccountLoan" table="ACCOUNT_LOAN" dynamic-update="true">
<id name="id" column="AL_ID" type="long">
<generator class="com.common.support.IdGenerator">
<param name="sequence">ALID_SEQ</param>
</generator>
</id>
<many-to-one name="account" class="com.master.model.Account" unique="true">
<column name="AL_AC_ID" not-null="true" />
</many-to-one>
<property name="loanA" column="AL_LOANA" type="big_decimal" />
<property name="loanB" column="AL_LOANB" type="big_decimal" />
</class>
</hibernate-mapping>
First of all, make your mapping look like described in the documentation. The one-to-one needs a property-ref attribute.
Then, make sure that you initialize the AccountLoan.account property when you want to attach an AccountLoan to an Account. Initializing the Account.accountLoan field is not sufficient.
I have a Hibernate mapping setup. The table is species, my Java class is Species. hibernate.cfg.xml points to mappings in species.hbn.xml
In my code I'm using a simple HQL query and then throwing the resultant Species instances into a "SpeciesLister" class (which I'm passing over to the presentation layer).
SpeciesLister speciesList = new SpeciesLister();
Query q = session.createQuery("SELECT s FROM Species s");
for (Species s : (List<Species>) q.list()){
speciesList.addSpecies(s);
}
The Species class looks like this:
package springwildlife;
public class Species implements Serializable
{
long id;
String commonName;
String latinName;
String order;
String family;
ArrayList<Sighting> sightings;
public Species()
{
}
public Species(String commonName, String latinName)
{
sightings = new ArrayList<Sighting>();
this.commonName = commonName;
this.latinName = latinName;
}
public long getId()
{
return id;
}
public String getCommonName()
{
return commonName;
}
public String getLatinName()
{
return latinName;
}
public String getOrder()
{
return order;
}
public String getFamily()
{
return family;
}
public ArrayList<Sighting> getSightings()
{
return sightings;
}
public void addSighting(Sighting s)
{
sightings.add(s);
}
public void setId(long id)
{
this.id = id;
}
public void setCommonName(String cn)
{
commonName = cn;
}
public void setLatinName(String ln)
{
commonName = ln;
}
public void setFamily(String f)
{
family = f;
}
public void setOrder(String o)
{
order = o;
}
}
My database schema looks like this:
CREATE TABLE species
(
id serial NOT NULL,
common_name text,
latin_name text,
order_name text,
family_name text,
CONSTRAINT id PRIMARY KEY (id)
)
species.hbn.xml looks like this:
<?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="springwildlife.Species" table="species">
<id name="id" type="java.lang.Long" column="id" >
<generator class="native">
<param name="sequence">species_id_seq</param>
</generator>
</id>
<property name="commonName" type="java.lang.String">
<column name="common_name" />
</property>
<property name="latinName" type="java.lang.String">
<column name="latin_name"/>
</property>
<property name="order" type="java.lang.String">
<column name="order_name"/>
</property>
<property name="family" type="java.lang.String">
<column name="family_name"/>
</property>
</class>
</hibernate-mapping>
My SpeciesLister instance gets a full slate of all the expected number of Species instances. However, when I examine the resultant Species instances, all their fields are null except for the id (long), all the others like familyName, latinName, commonName all are null in the mapped object.
This is unexpected and I can't figure out why it is happening. Am I doing something wrong?
I'm suspicious about two things, but I'm not sure of what to make of them:
I think the fact that the id is being property set, but not the other string fields might be a clue.
I suspect something might be wrong with the way I'm casting the objects into a list of Species instances.
The code looks ok. Without getting into debugger it's hard to tell for sure, however my guess is that you have compile time class instrumentation somewhere in the build. If that's a case, I've seen cases when assignment to actual field in the class is deferred until you call getter method.
So I suggest, that you put some print statements that rely on getters to get data instead of direct access to properties and see what gets printed.
Finally, please put # sign in front of names in comments (#Mark). This way, your correspondents will get notified and you may get response sooner.
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.