Techspace

IT happens only in IT

HibernateSystemException- Don’t change the reference to a collection with cascade=”all-delete-orphan”

This is not an error which I got. This is an error that bugged one of my friend for a few days.

The error is

org.springframework.orm.hibernate3.HibernateSystemException: Don’t change the reference to a collection with cascade=”all-delete-orphan”: com.test.Cat.kittens; nested exception is org.hibernate.HibernateException: Don’t change the reference to a collection with cascade=”all-delete-orphan”: com.test.Cat.kittens on 10.01.2009@15.26.33

<hibernate-mapping package="com.test">
       <class name="Cat" lazy="false">
			   ......
			   ......
			   ......

               <set name="kittens" table="kitten" order-by="kitten_name asc" inverse="true"                             cascade="all-delete-orphan">
               <key column="cat_id"/>
               <one-to-many class="Kitten"/>
           </set>
       </class>
</hibernate-mapping>

We researched a few solutions on the net. The following solutions are based mainly on the two sources
http://forum.springframework.org/showthread.php?t=25809
http://www.hibernate.org/117.html#A3

Since I myself did not get this problem I can’t give much details. And the solutions below may or may not work for you.

There are two ways to solve this problem
i) If posible switch to the latest version of the Hibernate. Even though it is not a bug in the Hibernate, some people reported that somehow this problem doesn’t appear in the new version of hibernate.

Caution: If your application uses Hibernate extensively then you might consider testing the application throughly after upgrade. If you can’t upgrade for some reasons, then read on

ii) If you can’t upgrade then as per the solutions provided on the forums, you should call clear() if you need to remove the collections marked as all-delete-orphan.
Fair enough. Makes sense, since you are cascading the delete you should inform Hibernate if you intend to remove the collection.

For example,
Instead of doing something like this.

	public void removeKittens(){
	  //Load Cat with kittens
	  Cat cat = getHibernateTemplate().get(Cat.class, 1234);
	  cat.setKittens(null);
	  getHibernateTemplate().save(cat);
	}

Do something like this

	public void removeKittens(){
	  //Load Cat with kittens
	  Cat cat = getHibernateTemplate().get(Cat.class, 1234);
	  cat.getKittens.clear();
	  getHibernateTemplate().save(cat);
	}

As I said this is not a bug in Hibernate’s older version. But somehow in the new version, as people reported on the forums, this problem is not there. That means you are not required to call clear(). I am not sure because I have not faced this problem myself.

February 13, 2009 Posted by | Hibernate | , , | 1 Comment

Hibernate error : org.hibernate.hql.ast.QuerySyntaxException: unexpected end of subtree

Update: Look at the comments for more information and possible solutions.

I got this error today.

Caused by: org.hibernate.hql.ast.QuerySyntaxException: unexpected end of subtree [select count(*)  from com.test.Fruits as fruit where fruit.fruitId in () order by fruit.fruitName desc ]
	at org.hibernate.hql.ast.QuerySyntaxException.convert(QuerySyntaxException.java:31)
	at org.hibernate.hql.ast.QuerySyntaxException.convert(QuerySyntaxException.java:24)
	at org.hibernate.hql.ast.ErrorCounter.throwQueryException(ErrorCounter.java:59)
	at org.hibernate.hql.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:235)
	at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:160)
	at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:111)
	at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:77)
	at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:56)
	at org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:72)
	at org.hibernate.impl.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:133)
	at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1113)
	at org.hibernate.impl.QueryImpl.list(QueryImpl.java:79)
	at com.test.FruitDAOServiceImpl.fruitCount(FruitDAOServiceImpl.java:682)
	at jrockit.reflect.VirtualNativeMethodInvoker.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(Unknown Source)
	at java.lang.reflect.Method.invoke(Ljava.lang.Object;[Ljava.lang.Object;I)Ljava.lang.Object;(Unknown Source)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:304)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:172)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:139)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:107)</code>

While there could be many reasons because of which this error comes. For me, the problem was that the parameter list I was passing was empty.

I was getting all the fruits for which fruit id is in the fruitIdList I was passing as the query parameter. If the fruitIdList is emply list then this problem comes. I solved it by conditionally framing query based on the list. That is instead of

public Long fruitCount(List<Long> fruitIdList){
	........
	Query fruitQuery = getSession().createQuery("select count(*)  from com.test.Fruits as fruit where fruit.fruitId in (:fruitIdList) order by fruit.fruitName desc ");
	fruitQuery.setParameterList("fruitIdList", fruitIdList);
	List<Long> fruitCountList = fruitQuery.list();
	..........
}

I did this

public Long fruitCount(List<Long> fruitIdList){
	........
	StringBuffer queryString = new StringBuffer("select count(*)  from com.test.Fruits as fruit ");

	if(fruitIdList !=null && !fruitIdList.isEmpty()){
		queryString.append(" where fruit.fruitId in (:fruitIdList) ");
	}

	queryString.append(" order by fruit.fruitName desc ");

	Query fruitQuery = getSession().createQuery(queryString.toString());
	if(fruitIdList !=null && !fruitIdList.isEmpty()){
		fruitQuery.setParameterList("fruitIdList", fruitIdList);
	}

	List<Long> fruitCountList = fruitQuery.list();
	..........
}

In short, append the collection parameter in the query and the query parameter only if the collection is non-empty.

December 9, 2008 Posted by | Hibernate | , , , , | 7 Comments

org.hibernate.TransientObjectException: object references an unsaved transient instance – save the transient instance before flushing:

I was getting this error today.
org.hibernate.TransientObjectException: object references an unsaved transient instance – save the transient instance before flushing:This is the problemTable A was referring to the talbe B using a foreign key

hbm.xml for A looked like this

<class name=”com.xxx.A” table=”A” schema=”TESTSCHEMA”>
<id name=”aId” type=”java.lang.Long”>
<column name=”A_ID” precision=”29″ scale=”0″ />
</id>…………………..
some more mapping elements
…………………..
…………………..
<many-to-one name=”bId” class=”com.xxx.B” fetch=”select”>
<column name=”B_ID” precision=”29″ scale=”0″ />
</many-to-one>

…………………..

I just want to save A with some new value and A will refer to B using some foreign key. But in my transaction I am not going to change B and save the changes. Therefore the many-to-one mapping above is wrong. It does not tell hibernate that class b is immutant. That is it is not going to change. Hibernate thinks that the referred table is not saved therefore it complains and says

org.hibernate.TransientObjectException: object references an unsaved transient instance – save the transient instance before flushing:

Please note that in this case B is transient object. If you don’t really want to save the value of B(transient object) in A , then to get rid of this problem change the many-to-one mapping as

update=”false” insert=”false” fetch=”select”>

But if you want to save the value of B then see my other post

That is, tell hibernate that you are not going to change the values of B, you are just fetching it.

 

January 14, 2008 Posted by | Hibernate | , | 18 Comments

ORA-01747: invalid user.table.column, table.column, or column specification

Today I got this error.

ORA-01747: invalid user.table.column, table.column, or column specification.

There could be many reasons why you can get this error. But the basic reason is the query which is finally getting executed to your database is wrong in some way. In my case, I had a column with column name as DESC. I got rid of this problem by simply dropping the table and creating a new one with column name DESCRIPTION instead of DESC. You may not be able to do that if the table is already existing with many records in it. :-)

Other reason could be that, if you are using named query your named query is not syntactically right.

No matter how the you get this error or for that matter any DB error in Hibernate, the best approach is to enable the show_sql variable in hibernate configuration and get the final query which hibernate is firing against the database.

Get this query and try running it directly in your database client. You can easily find out the culprit part of the query from there. Once you find out root cause of the problem you can think of workarounds or solution for this problem.

And yes, don’t forget to turn off the show_sql parameter after you are done with it. It will unnecessarily clutter your logs.

January 9, 2008 Posted by | Hibernate | , , | 10 Comments

   

Follow

Get every new post delivered to your Inbox.