-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: Working with collections with Detached objects
PostPosted: Thu May 08, 2008 7:50 am 
Newbie

Joined: Thu May 08, 2008 7:07 am
Posts: 5
Hi,
I have been trying to move away from OJB and on to hibernate for our application. Our application is a web application that I do not want to work with eager loading and with detached objects (to simplify migration and because there is little gained from it because our application displays all data up front).

I have started with the unit tests and everything was working fine, until I added a collection to my object. This collection is best represented as a bag/idbag. However, neither works.

I will start with a bag.

If I have a bag, all my test cases run, but I get the following error when I try to retrieve my object (Brand), add a new element to my collection (ExtraEnqField), it comes up with this error:

Code:
java.util.NoSuchElementException
   at java.util.AbstractList$Itr.next(AbstractList.java:427)
   at org.hibernate.collection.AbstractPersistentCollection$IteratorProxy.next(AbstractPersistentCollection.java:555)
   at au.com.tt.ccm.dao.BrandDAOTest.testUpdatingExistingBrandWithNewExtraEnq(BrandDAOTest.java:174)


Here is the test that fails:

Code:
public void testUpdatingExistingBrandWithNewExtraEnq() throws FileNotFoundException, IOException, Exception
    {
   SessionFactory sessionFactory = getSessionFactory(new HelperRoutines().getTestHibernateConfig("test.hibernate.cfg.xml"));
   BrandDAO brandDao = new BrandDAO(sessionFactory);
   
   Brand saveBrand = brandDao.retrieve("test9");

   ExtraEnqField extraEnqField = (ExtraEnqField)saveBrand.getExtraEnqFields().iterator().next();

   brandDao.save(saveBrand);
   
   Brand retrieveBrand = brandDao.retrieve("test9");   
   assertEquals(BrandTestHelper.equals(retrieveBrand, saveBrand), true);
   assertEquals(saveBrand.getExtraEnqFields().size(), retrieveBrand.getExtraEnqFields().size());
    }


It is using TestNG BTW. The tests use hypersonic, but the target database is Postgres.

Here is a cut down version of my binding:

Code:
<?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 package="au.com.tt.ccm.beans">

   <class name="Brand" table="brand" schema="public" lazy="false">

      <id name="brandId" column="brand_id">
         <generator class="assigned" />
      </id>
<!-- More fields here -->
      
      <bag name="extraEnqFields" table="extra_enq_field" lazy="false" cascade="all" fetch="join">
         <key column="brand"/>
         <composite-element class="ExtraEnqField" >
            <property name="label" column="label" type="string" />
            <property name="displayType" column="display_type"
               type="string" />
         </composite-element>
      </bag>
   </class>
</hibernate-mapping>


It looks like it is using a proxy, but I thought that using lazy="false" stops it from using a proxy. Why isn't Hibernate just loading the data directly into the Collection?

Here is my DAO, bean and SQL (cut down again)

BEAN
Code:
package au.com.tt.ccm.beans;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.LinkedList;
import java.util.Iterator;
import java.util.Date;
import java.util.Set;

public class Brand implements Serializable
{

    public Brand(String inBrandId)
    {
        mBrandId = inBrandId;
        mExtraEnqFields = new ArrayList<ExtraEnqField>();

    }

    public Brand()
    {
        mExtraEnqFields = new ArrayList<ExtraEnqField>();

    }



    public String getBrandId()
    {
        return (mBrandId);
    }





    public Collection<ExtraEnqField> getExtraEnqFields()
    {
        return (mExtraEnqFields);
    }

    public void setBrandId(String inBrandId)
    {
        mBrandId = inBrandId;
    }

    public void setExtraEnqFields(Collection<ExtraEnqField> inExtraEnqFields)
    {
        mExtraEnqFields = inExtraEnqFields;
    }
   

    public void addExtraEnqFields(ExtraEnqField inExtraEnqField)
    {       
        mExtraEnqFields.add(inExtraEnqField);       
    }
   
    @Override
    public int hashCode()
    {
   final int prime = 31;
   int result = 1;
   result = prime * result + ((mBrandId == null) ? 0 : mBrandId.hashCode());
   return result;
    }

    @Override
    public boolean equals(Object obj)
    {
   if (this == obj) return true;
   if (obj == null) return false;
   if (getClass() != obj.getClass()) return false;
   final Brand other = (Brand) obj;
   if (mBrandId == null)
   {
       if (other.getBrandId() != null) return false;
   }
   else if (!mBrandId.equals(other.getBrandId())) return false;
   return true;
    }
    String mBrandId;
    Collection<ExtraEnqField> mExtraEnqFields;
}


Code:
package au.com.tt.ccm.beans;

import java.io.Serializable;

import org.apache.commons.lang.builder.ToStringBuilder;

import au.com.tt.utils.CalypsoToStringStyles;;

public class ExtraEnqField implements Serializable
{

    public ExtraEnqField()
    {
    }   
   
    public String getLabel() { return(mLabel); }
   
    public String getDisplayType() { return(mDisplayType); }
     
    public void setLabel(String inLabel) { mLabel = inLabel; }
   
    public void setDisplayType(String inDisplayType) { mDisplayType = inDisplayType; }
   
    public int getId()
    {
        return mId;
    }

    public void setId(int inId)
    {
        mId = inId;
    }

    @Override
    public int hashCode()
    {
   final int prime = 31;
   int result = 1;
   result = prime * result + mId;
   return result;
    }

    @Override
    public boolean equals(Object obj)
    {
   if (this == obj) return true;
   if (obj == null) return false;
   if (getClass() != obj.getClass()) return false;
   final ExtraEnqField other = (ExtraEnqField) obj;
   if (mId != other.mId) return false;
   return true;
    }

    private String   mLabel;
    private String   mDisplayType;   
    private int      mId;   
}



DAO
Code:
package au.com.tt.ccm.dao;

import java.io.Serializable;
import java.util.List;

import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.classic.Session;
import org.hibernate.criterion.ExistsSubqueryExpression;

import au.com.tt.ccm.beans.*;
import au.com.tt.ccm.exceptions.DAOException;


public class BrandDAO implements Serializable
{
    public BrandDAO(SessionFactory inSessionFactory) throws DAOException
    {

   if (inSessionFactory == null)
       throw new DAOException("SessionFactory cannot be null");   
   mSessionFactory = inSessionFactory;
   
    }

    public SessionFactory getSessionFactory()
    {
        return mSessionFactory;
    }

    public boolean exists(String inBrandId)
    {
   Session existsSession = null;
   try
   {
       existsSession = mSessionFactory.openSession();
      
       String sql = "SELECT true FROM brand WHERE brand.brand_id = :brand_id LIMIT 1";
      
       Query existsQuery = existsSession.createSQLQuery(sql).setParameter("brand_id", inBrandId);

       boolean ret = existsQuery.list().iterator().hasNext();
       return(ret);
   }
   finally
   {
       if (existsSession != null)
      existsSession.close();
   }
    }


    public Brand retrieve(String inBrandId)
    {
   Session retrieveSession = null;
   Transaction tx = null;   
   Brand result = null;
   
   try
   {
       retrieveSession = mSessionFactory.openSession();
       tx = retrieveSession.beginTransaction();

       result = (Brand) retrieveSession.get(Brand.class, inBrandId, LockMode.NONE);

       tx.commit();
   }
   catch (RuntimeException e)
   {
       onRuntimeException(tx);
   }
   finally
   {
       retrieveSession.close();
   }
   
        return (result);
    }
   

    public void save(Brand inBrand)
    {
   Transaction tx = null;
   Session saveSession = null;
   try
   {
       saveSession = mSessionFactory.openSession();

       tx = saveSession.beginTransaction();

       saveSession.saveOrUpdate(inBrand);

       tx.commit();
   }
   catch (RuntimeException e)
   {
       onRuntimeException(tx);
       throw e;
   }
   finally
   {
       saveSession.close();
   }
    }   
   
    private void onRuntimeException(Transaction tx)
    {
   tx.rollback();   
    }
   
    SessionFactory mSessionFactory;
}


SQL

Code:
CREATE TABLE brand (
    brand_id character varying(8) NOT NULL,

);


CREATE TABLE extra_enq_field (
    id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL,
    brand character varying(8) NOT NULL,
    label character varying(30) NOT NULL,
    display_type character varying(15) NOT NULL
);


Now, I would love to use idbag, but that even more problems. For example, I setup the idbag like so:

Code:
<idbag name="extraEnqFields" table="extra_enq_field" cascade="all" lazy="false" fetch="join">
    <collection-id type="integer" column="id" >
      <generator class="identity"></generator>
    </collection-id>
    <key column="brand"/>
   <composite-element class="ExtraEnqField" >
       <property name="label" column="label" type="string" />     
          <property name="displayType" column="display_type" type="string" />
   </composite-element>
</idbag>


And I got errors like the following:

Code:
FAILED: testUpdatingExistingBrandWithNewExtraEnq
java.util.NoSuchElementException
   at java.util.AbstractList$Itr.next(AbstractList.java:427)
   at org.hibernate.collection.AbstractPersistentCollection$IteratorProxy.next(AbstractPersistentCollection.java:555)
   at au.com.tt.ccm.dao.BrandDAOTest.testUpdatingExistingBrandWithNewExtraEnq(BrandDAOTest.java:174)
... Removed 22 stack frames
FAILED: testSaveExistingBrandWithNewExtraEnq
java.lang.ClassCastException: org.hibernate.id.IdentifierGeneratorFactory$2
   at org.hibernate.type.IntegerType.set(IntegerType.java:41)
   at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:136)
   at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:116)
   at org.hibernate.persister.collection.AbstractCollectionPersister.writeIdentifier(AbstractCollectionPersister.java:807)
   at org.hibernate.persister.collection.AbstractCollectionPersister.insertRows(AbstractCollectionPersister.java:1359)
   at org.hibernate.action.CollectionUpdateAction.execute(CollectionUpdateAction.java:66)
   at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
   at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
   at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:170)
   at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
   at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
   at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
   at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
   at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
   at au.com.tt.ccm.dao.BrandDAO.save(BrandDAO.java:106)
   at au.com.tt.ccm.dao.BrandDAOTest.testSaveExistingBrandWithNewExtraEnq(BrandDAOTest.java:159)
... Removed 22 stack frames


Top
 Profile  
 
 Post subject: Something I forgot...
PostPosted: Thu May 08, 2008 8:05 am 
Newbie

Joined: Thu May 08, 2008 7:07 am
Posts: 5
Silly me, forgot to mention what version of Hibernate I am using.

I am using 3.2.5.ga downloaded via Maven.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.