-->
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.  [ 10 posts ] 
Author Message
 Post subject: Wrong number of columns?!?
PostPosted: Wed Mar 04, 2009 7:59 am 
Beginner
Beginner

Joined: Thu Feb 19, 2009 5:48 am
Posts: 37
Location: Glasgow, Scotland
Any ideas, looks ok to me

Code:
Mapping documents:
    <class name="edina.clive.domain.Layer" table="layers">
    <meta attribute="class-description">
      A layer object which holds a list of layer sub-objects and a list of Style names in place of a style object
    </meta>

    <!--  also db column layerbbox -->
        <composite-id>
           <key-property name="layerName" />
           <key-property name="productName"/>
        </composite-id>
       
       <property name="subLayers" column="subLayers" type="edina.clive.domain.hibernate.SubLayerUserType"/>
       
   <!-- TODO: Envelope -->
   
   <!-- Initial version of style in which there was no style table,
        only a comma separated list in a layer field, may be going
        back to this method once I figure out how to do it in Hibernate
       
        <property name="styles" type="edina.clive.domain.hibernate.StyleUserType">
           <column name="styleNames"/>
           <column name="styleTitles"/>
         URL?
        </property>
   -->
      
      <property name="layerTitle" />
      <property name="srs" column="layerSRS" />
      <property name="minimumScale" column="layerscalemin"/>
      <property name="maximumScale" column="layerscalemax"/>
    </class>



Code:
Full stack trace of any exception that occurs:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactoryOrder' defined in URL [file:src/main/webapp/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is org.hibernate.MappingException: property mapping has wrong number of columns: edina.clive.domain.Layer.subLayers type: edina.clive.domain.hibernate.SubLayerUserType
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1338)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
   at java.security.AccessController.doPrivileged(Native Method)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
   at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
   at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
   at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
   at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
   at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
   at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:423)
   at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:728)
   at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:380)
   at org.springframework.test.AbstractSingleSpringContextTests.createApplicationContext(AbstractSingleSpringContextTests.java:199)
   at org.springframework.test.AbstractSingleSpringContextTests.loadContextLocations(AbstractSingleSpringContextTests.java:179)
   at org.springframework.test.AbstractSingleSpringContextTests.loadContext(AbstractSingleSpringContextTests.java:158)
   at org.springframework.test.AbstractSpringContextTests.getContext(AbstractSpringContextTests.java:105)
   at org.springframework.test.AbstractSingleSpringContextTests.setUp(AbstractSingleSpringContextTests.java:87)
   at junit.framework.TestCase.runBare(TestCase.java:128)
   at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:69)
   at junit.framework.TestResult$1.protect(TestResult.java:106)
   at junit.framework.TestResult.runProtected(TestResult.java:124)
   at junit.framework.TestResult.run(TestResult.java:109)
   at junit.framework.TestCase.run(TestCase.java:120)
   at junit.framework.TestSuite.runTest(TestSuite.java:230)
   at junit.framework.TestSuite.run(TestSuite.java:225)
   at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
   at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: org.hibernate.MappingException: property mapping has wrong number of columns: edina.clive.domain.Layer.subLayers type: edina.clive.domain.hibernate.SubLayerUserType
   at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:441)
   at org.hibernate.mapping.RootClass.validate(RootClass.java:192)
   at org.hibernate.cfg.Configuration.validate(Configuration.java:1108)
   at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1293)
   at org.springframework.orm.hibernate3.LocalSessionFactoryBean.newSessionFactory(LocalSessionFactoryBean.java:814)
   at org.springframework.orm.hibernate3.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:732)
   at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.afterPropertiesSet(AbstractSessionFactoryBean.java:211)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1369)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1335)
   ... 31 more


Code:
Custom UserType:
package edina.clive.domain.hibernate;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.type.Type;
import org.hibernate.usertype.CompositeUserType;

import edina.clive.domain.Layer;

/**
* @author Ross Drew
*
* Custom domain object user type for list of sub layers inside a layer
*/
public class SubLayerUserType implements CompositeUserType {

   @Override
   public Object assemble(Serializable cached, SessionImplementor session,
         Object owner) throws HibernateException {
      // TODO Auto-generated method stub
      return null;
   }

   @Override
   public Object deepCopy(Object value) throws HibernateException {
      // TODO Auto-generated method stub
      return null;
   }

   @Override
   public Serializable disassemble(Object value, SessionImplementor session)
         throws HibernateException {
      // TODO Auto-generated method stub
      return null;
   }

   @Override
   public boolean equals(Object x, Object y) throws HibernateException {
      return (x == null) ? (y == null) : x.equals(y);
   }

   @Override
   public String[] getPropertyNames() {
      return new String[] {"layerName","productName","subLayers","layerTitle","srs","minimumScale","maximumScale"};
     
   }

   @Override
   public Type[] getPropertyTypes() {
      return new Type[] {Hibernate.STRING, Hibernate.STRING, Hibernate.STRING, Hibernate.STRING, Hibernate.STRING,Hibernate.DOUBLE,Hibernate.DOUBLE};
   }

   @Override
   public int hashCode(Object x) throws HibernateException {
      // TODO Auto-generated method stub
      return 0;
   }

   @Override
   public boolean isMutable() {
      return false;
   }

   @Override
   public Object nullSafeGet(ResultSet rs, String[] names,
         SessionImplementor session, Object owner) throws HibernateException,
         SQLException {
     
      String rSubLayers = (String)Hibernate.STRING.nullSafeGet(rs, names[0]);
     
      /*DEBUG*///System.out.println("Returned: "+rSubLayers);
     /*DEBUG*///System.out.println("Owner: "+owner.toString());
     
      HashSet<Layer> returnedLayers = new HashSet<Layer>();
     
      for (String lyrName : rSubLayers.split(",")){
        Layer lyr = (Layer) session.getFactory().getCurrentSession().get(Layer.class, lyrName.trim()); //TODO: second argument??
         returnedLayers.add(lyr);
      }
      /*DEBUG*///System.out.println("Retrieved: "+returnedLayers.getClass());
      return returnedLayers;
   }

   @Override
   public void nullSafeSet(PreparedStatement st, Object value, int index,
         SessionImplementor session) throws HibernateException, SQLException {
     
      if (value == null)
         throw new IllegalArgumentException( "Received object in nullSafeSet was null - " + returnedClass() );

      if (!(value instanceof Set
            && (((Set)value).iterator().next()) instanceof Layer)){
         throw new IllegalArgumentException( "Received object in nullSafeSet was " + value.getClass().getName() + " in " + returnedClass() );
      }
     
      StringBuilder subLayers = new StringBuilder("");
      if (value == null) {
         st.setString(index, "");
       } else {
          //Build the comma separated lists for database
             for (Layer lyr : (Set<Layer>)value){//if this is not a set of layers, the exception would have been thrown already
             //Insert layer into layer table
                session.getFactory().getCurrentSession().save(lyr);
                subLayers.append(lyr.getLayerName()+",");
             }
          //Remove additional comma
             subLayers = subLayers.deleteCharAt(subLayers.length()-1);
       }
     
      Hibernate.STRING.nullSafeSet(st, subLayers.toString(), index);
     
   }

   @Override
   public Object replace(Object original, Object target,
         SessionImplementor session, Object owner) throws HibernateException {
      // TODO Auto-generated method stub
      return null;
   }

   @Override
   public Class returnedClass() {
      return Layer[].class;
   }
   
   @Override
   public Object getPropertyValue(Object component, int property)
         throws HibernateException {
      if (!(component instanceof Layer)){
         throw new IllegalArgumentException("Unknown component: "+component);
      }
     
      Layer layer = (Layer)component;
      String result;
     
      switch(property){
      case 0:
         result = layer.getLayerName();
         break;
      case 1:
         result = layer.getProductName();
         break;
      case 2:
      //Build layer list string
         StringBuilder layerList = new StringBuilder("");
         for (Layer l : layer.getLayers()){
            layerList.append(l.getLayerName()+",");
         }
     //Remove additional comma
         result = layerList.substring(0, layerList.length()-1);
         
      case 3:
         result = layer.getTitle();
         break;
         
      case 4:
         result = layer.getSrs();
         break;
         
      case 5:
         return layer.getMinimumScale();
     
      case 6:
         return layer.getMaximumScale();
         
      default:
         throw new IllegalArgumentException("Unknown property: "+property);
      }
      return result;
   }

   @Override
   public void setPropertyValue(Object component, int property, Object value){
      if (!(component instanceof Layer)){
         throw new IllegalArgumentException( "Received object in setPropertyValue was " + component.getClass().getName() + " in " + returnedClass() );
      }
      Layer layer = (Layer)component;
     
      //XXX: Add some type checking here?
      switch(property){
      case 0:
         layer.setLayerName((String)value);
         break;
         
      case 1:
         layer.setProductName((String)value);
         break;
         
      case 2:
       //TODO: what to do with this?
         System.out.println("Case 2, component:"+component.getClass()+", value:"+value.getClass());
         
      case 3:
         layer.setTitle((String)value);
         break;
         
      case 4:
        layer.setSrs((String)value);
        break;
         
      case 5:
        layer.setMinimumScale((Double)value);
        break;
     
      case 6:
         layer.setMaximumScale((Double)value);
         break;
         
      default:
         throw new IllegalArgumentException("Unknown property: "+property);
      }
   }

}

_________________
##############################
If I helped, rate my comment, I have plenty of stupid questions to ask that I need credit for ;)
##############################


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 04, 2009 9:21 am 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
I have not used a CompositeUserType myself, but I guess the number of columns specified in the <property> tag must match the number of properties returned by SubLayerUserType.getPropertyTypes() and getPropertyNames().

Eg. you would need:

Code:
<property name="subLayers" type="edina.clive.domain.hibernate.SubLayerUserType">
<column name="layerName" />
<column name="productName" />
... and so on
</property>


I don't understand how you implementation of nullSafeGet() / nullSafeSet() relates to this and to the returnedClass() method. returnedClass() says that you return a Layer[], but nullSafeGet() returns a Set and nullSafeSet() expects a Set as value and not a Layer[].

Are you trying to store a comma-separated list of references to other layers inside a single string column? If so, why not simply map a <many-to-one name="parent" type="Layer" /> instead?


Top
 Profile  
 
 Post subject: Well...
PostPosted: Wed Mar 04, 2009 9:41 am 
Beginner
Beginner

Joined: Thu Feb 19, 2009 5:48 am
Posts: 37
Location: Glasgow, Scotland
To be honest I didn't really understand the use of getProperty...() but you were quite right, it was because it should have only been returning a String as it only maps to one database column.

What I am trying to do it have a table of Layers and inside each Layer can have any amount of sub layers whose names are contained in the database field as a comma separated list. Wont a many-to-one relation simply add a foreign key to the sub layers? Because I dont want this, I want the only link between them be the comma separated list of names.

_________________
##############################
If I helped, rate my comment, I have plenty of stupid questions to ask that I need credit for ;)
##############################


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 04, 2009 9:48 am 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
Have a look at the Parent/Child example in the Hibernate documentation. http://www.hibernate.org/hib_docs/v3/re ... bidir.html


Top
 Profile  
 
 Post subject: But
PostPosted: Wed Mar 04, 2009 10:37 am 
Beginner
Beginner

Joined: Thu Feb 19, 2009 5:48 am
Posts: 37
Location: Glasgow, Scotland
Yes but in that example there is a foreign key in the child table linking it to the parent. I want the parent to manage the link by way of the comma separated list

_________________
##############################
If I helped, rate my comment, I have plenty of stupid questions to ask that I need credit for ;)
##############################


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 04, 2009 12:39 pm 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
Quote:
I want the parent to manage the link by way of the comma separated list


Why? To me it seems like a complicated solution to something that Hibernate has built-in support for.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 04, 2009 1:00 pm 
Beginner
Beginner

Joined: Thu Feb 19, 2009 5:48 am
Posts: 37
Location: Glasgow, Scotland
It does seem like a complicated solution. Unfortunately i've been given the domain objects and the database schema and told to get them to work together through Hibernate without modification. Apparently it's because they are trying to avoid as many Joins as possible.

Is it possible?

_________________
##############################
If I helped, rate my comment, I have plenty of stupid questions to ask that I need credit for ;)
##############################


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 04, 2009 1:17 pm 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
With a parent/child relationship you will not get any joins if you don't want to. With your current solution you instead get the "infamous" n+1 select problem. Your nullSafeGet() method will issue one SELECT for each sublayer.
And that is far worse than a join, which can be used to select a layer and it's sublayers with a single query.

It may not matter in reality if your database is small. I have personally experienced a 100-fold performance gain when using a join instead of n+1 selects. But that query returned over 100 000 items.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 04, 2009 1:18 pm 
Beginner
Beginner

Joined: Thu Feb 19, 2009 5:48 am
Posts: 37
Location: Glasgow, Scotland
Well, like I say, I don't have a choice. I'm "the middle man" as they say :P

Any idea if it can be done this way?

_________________
##############################
If I helped, rate my comment, I have plenty of stupid questions to ask that I need credit for ;)
##############################


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 04, 2009 3:01 pm 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
I rest my case. Good luck.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 10 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.