views:

447

answers:

1

I am using JPA/Spring/Hibernate as my persistence mechanism for my application. Currently I am running into unit test problems where when I ask for some objects I get the right amount returned from the DAO that correspond to the number of rows in the database, but they are all of the exact same instance. Here is the findByName() method that is causing me the problem.

public class ActionDefinitionDaoJpa extends JpaDaoSupport implements IActionDefinitionDao {
    public List findByName( String name ) {
        return getJpaTemplate().find("from ActionDefinition where listenerName = ?", name );
    } 
} 

This method works without any errors. I am testing this at the DAO layer and not the Service layer so I have no transactions introduced any where in the test. I don't know if it is transactional or not. If I take the SQL that the JPA produces and execute it I get the right resultset from the database.

Here is my spring configuration file and persistence.xml file

<beans>

    <!-- My Dao in Test -->
    <bean id="actionDefinitionDao" class="com.putnam.compliance.cme.dao.actions.jpa.ActionDefinitionDaoJpa">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">

          <property name="persistenceXmlLocation" value="classpath:persistence.xml" />
          <property name="persistenceUnitName"    value="cmeJpa" />
          <property name="dataSource"             ref="dataSource"/>

          <property name="jpaVendorAdapter">
               <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                    <property name="database"         value="ORACLE"/>
                    <property name="showSql"          value="true"/>
                    <property name="generateDdl"      value="false"/>
                    <property name="databasePlatform" value="org.hibernate.dialect.OracleDialect"/>
               </bean>
          </property>

          <property name="jpaPropertyMap">
               <map>
                    <entry key="hibernate.transaction.flush_before_completion" value="true"/>
                    <entry key="hibernate.transaction.auto_close_session"      value="true"/>
                    <entry key="hibernate.current_session_context_class"       value="jta"/>
                    <entry key="hibernate.connection.release_mode"             value="auto"/>                            
               </map>
          </property>

          <property name="jpaDialect">
               <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
          </property>

    </bean>


    <!--  
          DataSource to talk to Database Note: these values are pulled in by the .properties files
     -->
    <bean id="localDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
         <property name="driverClassName" value="${dataSource.driverClassName}" />
         <property name="url"             value="${dataSource.url}" />
         <property name="username"        value="${dataSource.username}" />
         <property name="password"        value="${dataSource.password}" />
    </bean>
    <alias name="localDataSource" alias="dataSource"></alias>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
         <property name="entityManagerFactory" ref="entityManagerFactory"/>
         <property name="dataSource" ref="dataSource"/>
    </bean>

</bean>

Here is my persistence.xml file

<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
<!--  
    <persistence-unit name="cmeJpa" transaction-type="JTA">
-->
    <persistence-unit name="cmeJpa" transaction-type="RESOURCE_LOCAL">
          <class>com.putnam.compliance.cme.model.actions.ActionSequence</class>
          <class>com.putnam.compliance.cme.model.actions.ActionDefinition</class>
          <class>com.putnam.compliance.cme.model.actions.ActionXmlDefinition</class>
          <exclude-unlisted-classes/>
    </persistence-unit>

</persistence>

Here is my ActionDefinition JPA bean


@Entity
@Table(name="PUT_M_DEFINITION")
public class ActionDefinition implements java.io.Serializable {


    public ActionDefinition() {
    }

    @Id
    @Column(name="LISTENER_NAME")
    public String getListenerName() {
        return listenerName;
    }
    public void setListenerName( String n ) {
        listenerName = n;
    }
    @Column(name="CONTEXT")
    public String getContext() {
        return context;
    }
    public void setContext( String n ) {
        context = n;
    }
    @Column(name="DATA")
    public String getData() {
        return data;
    }
    public void setData( String n ) {
        data = n;
    }
    @Column(name="NOTES")
    public String getNotes() {
        return notes;
    }
    public void setNotes( String n ) {
        notes = n;
    }
    @Column(name="EMAIL_ID")
    public String getEmailId() {
        return emailId;
    }
    public void setEmailId( String n ) {
        emailId = n;
    }

   ...
   ...
}

I've played with many different combinations like change from LocalContainerEntityManagerFactoryBean to a LocalEntityManagerFactoryBean.

I got runtime errors about persistenceXmlLocation property not present.

I also tried changing the transaction-type in persistance.xml file to "JTA" that did not seem to work it actually broke it.

At this point I am floundering and not sure where my problem is. Again I run this in JUnit so it is not inside any container and may be when moved to Production.

Any pointers would be appreciated; thanks

A: 

Thank you for the input given: I've determine what my problem is. The reason I was getting back instance of ActionDefinition that were the exact same was because my table contained a Composite Primary Key.

Here is how I resolved my problem with my model object. I changed my model object to contain a Composite class called ActionDefinitionPK


@Entity
@Table(name="PUT_M_DEFINITION")
@IdClass(ActionDefinitionPK.class)
public class ActionDefinition implements java.io.Serializable {


    @Id
    @Column (name="LISTENER_NAME")
    private String  listenerName     = null;
    @Id
    @Column (name="CONTEXT")
    private String  context          = null;


    @Column (name="DATA")
    private String  data             = null;
    @Column (name="NOTES")
    private String  notes            = null;
    @Column (name="EMAIL_ID")
    private String  emailId          = null;


Here is the Composite class and its definition


@Embeddable
public class ActionDefinitionPK implements java.io.Serializable {


    @Column (name="LISTENER_NAME")
    private String  listenerName     = null;
    @Column (name="CONTEXT")
    private String  context          = null;

    /**
     * Constructor
     */
    public ActionDefinitionPK() {
    }
    public ActionDefinitionPK(String name, String context) {
        setListenerName( name );
        setContext( context );
    }
}

Thanks to all those who provided help.
Peter Delaney