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.  [ 15 posts ] 
Author Message
 Post subject: Another insert executed when update should be happening
PostPosted: Thu Mar 02, 2006 7:57 pm 
Newbie

Joined: Thu Mar 02, 2006 7:47 pm
Posts: 8
I am new to Hibernate and using it in a web application. I've got it working great to save a record but when I try and do an update(call session.save(xxx)) with the ID already set, i get a new record inserted instead of updated.

Here is my mapping:
Code:
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="gov.fws.rmad.domain">
    <class name="ManagementUnitDO" table="management_unit_t">

        <id name="id"
           type="long"
           column="management_unit_sid"
           unsaved-value="null">
         <generator class="native"/>
        </id>

      <version type="dbtimestamp" column="updated_on" name="lastModifiedDate" generated="always"/>
   
        <property name="lastModifiedUsername" type="string" column="updated_by"/>
        <property name="createdUsername" type="string" column="created_by" insert="true" update="false"/>
       
        <property name="createdDate" column="created_on" type="timestamp" insert="true" update="false" />

       
        <property name="orgcode" type="string" column="orgcode"/>
        <property name="region" type="string" column="region"/>
        <property name="acres" type="integer" column="acres"/>
        <property name="unitName" type="string" column="unit_name"/>
       


    </class>
</hibernate-mapping>


Here is my Data Object
Code:
package gov.fws.rmad.domain;

import gov.fws.common.util.StringFormat;

import java.text.NumberFormat;
import java.text.ParseException;

/**
* A simple value object for the RMAD Management Unit database tables.
*
* Contents &copy; Copyright 2005 U.S. Fish and Wildlife Service
*
* @author  RAS
* @created 07/18/2005
*/
public class ManagementUnitDO extends RmadBaseDO implements Orgcode
{
  /** Number of acres in management unit. */
  private int acres;
   
  /** Organization Code. */
  private String orgcode;
 
  /** Region ID. */
  private String region;
 
  /** Management unit name. */
  private String unitName;

/**
  * Default constructor.
  */
  public ManagementUnitDO() {}


 
/**
  * Constructor.
  * @param aId - management unit id.
  */
  public ManagementUnitDO(long aId)
  {
    setId(aId);
  } 
 
  public String getUnitLabel(){
     
      StringBuffer sb = new StringBuffer(unitName);
      sb.append(" - ");
      sb.append(acres);
     
      return sb.toString();
     
  }
 
/**
  * Getter for number of acres.
  * @return <code>int</code> containing acreage.
  */
  public int getAcres() {
    return acres;
  } 
   
/**
  * Formatted getter for acres.
  *
  * @return acres.
  */
  public String getAcresFormatted() {
    if (acres == 0) {
      return "";
    } else {
      return new Integer(acres).toString();
    }
  }
   
/**
  * Getter for organization code.
  * @return <code>String</code> containing organization code.
  */
  public String getOrgcode() {
    return orgcode;
  }
 
  /**
   * Getter for region id.
   * @return <code>String</code> containing region id.
   */
  public String getRegion() {
     return region;
  }
 
/**
  * Getter for unit name.
  * @return <code>String</code> containing the unit name.
  */
  public String getUnitName() {
    return unitName;
  }
 
/**
  * Setter for number of acres.
  * @param aAcres - number of acres.
  */ 
  public void setAcres(int aAcres) {
    acres = aAcres; 
  } 
   
/**
  * Formatted Setter for acres.
  * @param aAcres - number of acres.
  */
  public void setAcresFormatted(String aAcres) {
    try {
      acres = NumberFormat.getNumberInstance().parse(aAcres).intValue();
    } catch (ParseException nfe) {
      acres = 0;
    }
  }
   
/**
  * Setter for organization code.
  * @param aOrgCode - organization code.
  */ 
  public void setOrgcode(String aOrgCode) {
    orgcode = aOrgCode; 
  }
   
  /**
   * Setter for the region id
   * @param aRegion - region id
   */
  public void setRegion(String aRegion) {
     region = aRegion;
  }
 
/**
  * Setter for management unit name.
  * @param aUnitName - management unit name.
  */ 
  public void setUnitName(String aUnitName) {
    unitName = aUnitName; 
  }
}


Here is some of the output from the console
Code:
16:45:13,025 INFO  [STDOUT] Hibernate: select current_timestamp
16:45:13,040 INFO  [STDOUT] Hibernate: insert into management_unit_t (updated_by, created_by, created_on, orgcode, region, acres, unit_name) values (?, ?, ?, ?, ?, ?, ?) select scope_identity()
16:45:13,087 INFO  [STDOUT] Hibernate: select management_.updated_on as updated2_25_ from management_unit_t management_ where management_.management_unit_sid=?


Here is my Struts Action where object is saved
Code:
         managementUnit.setRegion(muForm.getAdminRegion());
         System.out.printlb(managementUnit.getId());
        managementUnit.setCreatedUsername(request.getRemoteUser());
        managementUnit.setLastModifiedUsername(request.getRemoteUser());
        managementUnit.setCreatedDate(new Timestamp( new Date().getTime()));;
        sess.save(managementUnit);


The id output from the system out is set and correct, so it seems like an update should happen

Any help is appreciated!
Thank You


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 02, 2006 8:18 pm 
Expert
Expert

Joined: Mon Jan 09, 2006 5:01 pm
Posts: 311
Location: Sacramento, CA
then try saveorUpdate instead of save.

_________________
-JT

If you find my replies helpful, please rate by clicking 'Y' on them. I appreciate it.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 02, 2006 9:15 pm 
Newbie

Joined: Thu Mar 02, 2006 7:47 pm
Posts: 8
jt_1000 wrote:
then try saveorUpdate instead of save.


I tried that and got the same results. thanks you for repsonding though!


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 1:17 am 
Expert
Expert

Joined: Mon Jan 09, 2006 5:01 pm
Posts: 311
Location: Sacramento, CA
try sess.load(ManagementUnitDao.class,id) then make your changed, and issue saveOrUpdate...
are you in a web environment? Saving your sessions? or SessionFactory?
The items is obviously detached from hibernate - so either session.merge(object) or load...yet it should update if you filled in the ID (due to the unsaved-value=null) ...hummm.

_________________
-JT

If you find my replies helpful, please rate by clicking 'Y' on them. I appreciate it.


Last edited by jt_1000 on Fri Mar 03, 2006 2:16 am, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 2:15 am 
Newbie

Joined: Thu Mar 02, 2006 7:47 pm
Posts: 8
jt_1000 wrote:
try sess.load(ManagementUnitDao.class,id) then make your changed, and issue saveOrUpdate... I think your running into the problems due to the versioning timestamp.


So are you saying load up the object then set all the properties with their "updated" values and then call save. Doesn't seem like that is how it is supposed to work but I will give it a shot

As far as the time stamps for versioning go, what do you see as the problem? Should I switch to integers? Again I though this was ok to do

Thanks again


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 2:19 am 
Expert
Expert

Joined: Mon Jan 09, 2006 5:01 pm
Posts: 311
Location: Sacramento, CA
sorry -- i edited my answer - and got rid of the timestamp issue - on second thought that shouldn't be it...at all. The load before the save will work for sure.

_________________
-JT

If you find my replies helpful, please rate by clicking 'Y' on them. I appreciate it.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 12:16 pm 
Newbie

Joined: Thu Mar 02, 2006 7:47 pm
Posts: 8
jt_1000 wrote:
sorry -- i edited my answer - and got rid of the timestamp issue - on second thought that shouldn't be it...at all. The load before the save will work for sure.


Although it might work, it still seems confusing to me. After you specified an unsaved-value in the ID mapping and the object is loaded with an ID, why can't hibernate figure out if the object needs to be inserted or updated? Isn't that what the saveOrUpdate() method is meant to do?
Thanks for helping to clarify this.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 12:18 pm 
Expert
Expert

Joined: Mon Jan 09, 2006 5:01 pm
Posts: 311
Location: Sacramento, CA
the answer to that is manifested by you answering my questions in the post on env - 2nd one back.

_________________
-JT

If you find my replies helpful, please rate by clicking 'Y' on them. I appreciate it.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 12:27 pm 
Newbie

Joined: Thu Mar 02, 2006 7:47 pm
Posts: 8
jt_1000 wrote:
the answer to that is manifested by you answering my questions in the post on env - 2nd one back.


Sorry didn't see that question

Yes I am in a web env. The id is a hidden form field and I have verified by System.out that it is set when the request comes into my save action

I am using the HibernateUtil/HibernateThreadFilter pattern which filters all requests into the struts servlet

Thanks again


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 1:22 pm 
Expert
Expert

Joined: Mon Jan 09, 2006 5:01 pm
Posts: 311
Location: Sacramento, CA
are you saving at application level session and/or sessionfactory? if not at what level are you saving them? Are you using 2nd level caching?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 1:51 pm 
Newbie

Joined: Thu Mar 02, 2006 7:47 pm
Posts: 8
jt_1000 wrote:
are you saving at application level session and/or sessionfactory? if not at what level are you saving them? Are you using 2nd level caching?


The session factory is established and managed by the HibernateUtil class
Code:
package gov.fws.rmad.util;

import org.hibernate.*;
import org.hibernate.cfg.*;
import org.apache.commons.logging.*;

import javax.naming.*;

/**
* Basic Hibernate helper class for Hibernate configuration and startup.
* <p>
* Uses a static initializer to read startup options and initialize
* <tt>Configuration</tt> and <tt>SessionFactory</tt>.
* <p>
* This class also tries to figure out if JNDI binding of the <tt>SessionFactory</tt>
* is used, otherwise it falls back to a global static variable (Singleton). If
* you use this helper class to obtain a <tt>SessionFactory</tt> in your code,
* you are shielded from these deployment differences.
* <p>
* Another advantage of this class is access to the <tt>Configuration</tt> object
* that was used to build the current <tt>SessionFactory</tt>. You can access
* mapping metadata programmatically with this API, and even change it and rebuild
* the <tt>SessionFactory</tt>.
* <p>
* If you want to assign a global interceptor, set its fully qualified
* class name with the system (or hibernate.properties/hibernate.cfg.xml) property
* <tt>hibernate.util.interceptor_class</tt>. It will be loaded and instantiated
* on static initialization of HibernateUtil; it has to have a
* no-argument constructor. You can call <tt>HibernateUtil.getInterceptor()</tt> if
* you need to provide settings before using the interceptor.
* <p>
* Note: This class supports annotations by default, hence needs JDK 5.0
* and the Hibernate Annotations library on the classpath. Change the single
* commented line in the source to make it compile and run on older JDKs with
* XML mapping files only.
* <p>
* Note: This class supports only one data store. Support for several
* <tt>SessionFactory</tt> instances can be easily added (through a static <tt>Map</tt>,
* for example). You could then lookup a <tt>SessionFactory</tt> by its name.
*
* @author [email protected]
*/
public class HibernateUtil {

    private static Log log = LogFactory.getLog(HibernateUtil.class);

    private static final String INTERCEPTOR_CLASS = "hibernate.util.interceptor_class";

    private static Configuration configuration;
    private static SessionFactory sessionFactory;

    static {
        // Create the initial SessionFactory from the default configuration files
        try {


            // Replace with Configuration() if you don't use annotations or JDK 5.0
            configuration = new Configuration();

            // This custom entity resolver supports entity placeholders in XML mapping files
            // and tries to resolve them on the classpath as a resource
            configuration.setEntityResolver(new ImportFromClasspathEntityResolver());

            // Read not only hibernate.properties, but also hibernate.cfg.xml
            configuration.configure("/WEB-INF/xml/rmad_hibernate.cfg.xml");
            configuration.addClass(gov.fws.rmad.domain.OperatorDO.class);
            configuration.addClass(gov.fws.rmad.domain.ManagementUnitDO.class);
            configuration.addClass(gov.fws.rmad.domain.ManagementActionDO.class);

            // Set global interceptor from configuration
            setInterceptor(configuration, null);

            if (configuration.getProperty(Environment.SESSION_FACTORY_NAME) != null) {
                // Let Hibernate bind the factory to JNDI
                configuration.buildSessionFactory();
            } else {
                // or use static variable handling
                sessionFactory = configuration.buildSessionFactory();
            }

        } catch (Throwable ex) {
            // We have to catch Throwable, otherwise we will miss
            // NoClassDefFoundError and other subclasses of Error
            log.error("Building SessionFactory failed.", ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    /**
     * Returns the original Hibernate configuration.
     *
     * @return Configuration
     */
    public static Configuration getConfiguration() {
        return configuration;
    }

    /**
     * Returns the global SessionFactory.
     *
     * @return SessionFactory
     */
    public static SessionFactory getSessionFactory() {
        SessionFactory sf = null;
        String sfName = configuration.getProperty(Environment.SESSION_FACTORY_NAME);
        if ( sfName != null) {
            log.debug("Looking up SessionFactory in JNDI.");
            try {
                sf = (SessionFactory) new InitialContext().lookup(sfName);
            } catch (NamingException ex) {
                throw new RuntimeException(ex);
            }
        } else {
            sf = sessionFactory;
        }
        if (sf == null)
            throw new IllegalStateException("SessionFactory not available.");
        return sf;
    }

    /**
     * Closes the current SessionFactory and releases all resources.
     * <p>
     * The only other method that can be called on HibernateUtil
     * after this one is rebuildSessionFactory(Configuration).
     */
    public static void shutdown() {
        log.debug("Shutting down Hibernate.");
        // Close caches and connection pools
        getSessionFactory().close();

        // Clear static variables
        configuration = null;
        sessionFactory = null;
    }


    /**
     * Rebuild the SessionFactory with the static Configuration.
     * <p>
     * This method also closes the old SessionFactory before, if still open.
     * Note that this method should only be used with static SessionFactory
     * management, not with JNDI or any other external registry.
     */
     public static void rebuildSessionFactory() {
        log.debug("Using current Configuration for rebuild.");
        rebuildSessionFactory(configuration);
     }

    /**
     * Rebuild the SessionFactory with the given Hibernate Configuration.
     * <p>
     * HibernateUtil does not configure() the given Configuration object,
     * it directly calls buildSessionFactory(). This method also closes
     * the old SessionFactory before, if still open.
     *
     * @param cfg
     */
     public static void rebuildSessionFactory(Configuration cfg) {
        log.debug("Rebuilding the SessionFactory from given Configuration.");
        synchronized(sessionFactory) {
            if (sessionFactory != null && !sessionFactory.isClosed())
                sessionFactory.close();
            if (cfg.getProperty(Environment.SESSION_FACTORY_NAME) != null)
                cfg.buildSessionFactory();
            else
                sessionFactory = cfg.buildSessionFactory();
            configuration = cfg;
        }
     }

    /**
     * Register a Hibernate interceptor with the current SessionFactory.
     * <p>
     * Every Session opened is opened with this interceptor after
     * registration. Has no effect if the current Session of the
     * thread is already open, effective on next close()/getCurrentSession().
     * <p>
     * Attention: This method effectively restarts Hibernate. If you
     * need an interceptor active on static startup of HibernateUtil, set
     * the <tt>hibernateutil.interceptor</tt> system property to its
     * fully qualified class name.
     */
    public static SessionFactory registerInterceptorAndRebuild(Interceptor interceptor) {
        log.debug("Setting new global Hibernate interceptor and restarting.");
        setInterceptor(configuration, interceptor);
        rebuildSessionFactory();
        return getSessionFactory();
    }

    public static Interceptor getInterceptor() {
        return configuration.getInterceptor();
    }

    /**
     * Resets global interceptor to default state.
     */
    public static void resetInterceptor() {
        log.debug("Resetting global interceptor to configuration setting");
        setInterceptor(configuration, null);
    }

    /**
     * Either sets the given interceptor on the configuration or looks
     * it up from configuration if null.
     */
    private static void setInterceptor(Configuration configuration, Interceptor interceptor) {
        String interceptorName = configuration.getProperty(INTERCEPTOR_CLASS);
        if (interceptor == null && interceptorName != null) {
            try {
                Class interceptorClass =
                        HibernateUtil.class.getClassLoader().loadClass(interceptorName);
                interceptor = (Interceptor)interceptorClass.newInstance();
            } catch (Exception ex) {
                throw new RuntimeException("Could not configure interceptor: " + interceptorName, ex);
            }
        }
        if (interceptor != null) {
            configuration.setInterceptor(interceptor);
        } else {
            configuration.setInterceptor(EmptyInterceptor.INSTANCE);
        }
    }

}



And here is the HibernateThreadFilter class that is a servlet filter in the web.xml
Code:
package gov.fws.rmad.app.servlet;

import org.apache.commons.logging.*;
import org.hibernate.*;
import gov.fws.rmad.util.HibernateUtil;

import javax.servlet.*;
import javax.servlet.Filter;
import java.io.IOException;

/**
* A servlet filter that provides a thread-bound session-per-request.
* <p>
* This filter should be used if your <tt>hibernate.current_session_context_class</tt>
* configuration is set to <tt>thread</tt> and you are not using JTA/CMT. You can use
* this filter for a thread-bound <tt>Session</tt>, either with resource-local transactions
* (direct JDBC) or user-managed JTA transactions. Set your
* <tt>hibernate.transaction.factory_class</tt> accordingly.
* <p>
* An alternative, more flexible solution is <tt>TransactionInterceptor</tt>
* that can be applied to any pointcut with JBoss AOP.
* <p>
* Note that you should not use this interceptor out-of-the-box with enabled optimistic
* concurrency control. Apply your own compensation logic for failed conversations, this
* is totally dependent on your applications design.
*
* @see org.hibernate.ce.auction.persistence.TransactionInterceptor
*
* @author [email protected]
*/
public class HibernateThreadFilter implements Filter {

    private static Log log = LogFactory.getLog(HibernateThreadFilter.class);

    private SessionFactory sf;

    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain)
            throws IOException, ServletException {

        try {
            log.debug("Starting a database transaction");
            sf.getCurrentSession().beginTransaction();

            // Call the next filter (continue request processing)
            chain.doFilter(request, response);

            // Commit and cleanup
            log.debug("Committing the database transaction");
            sf.getCurrentSession().getTransaction().commit();

        } catch (StaleObjectStateException staleEx) {
            log.error("This interceptor does not implement optimistic concurrency control!");
            log.error("Your application will not work until you add compensation actions!");
            // Rollback, close everything, possibly compensate for any permanent changes
            // during the conversation, and finally restart business conversation. Maybe
            // give the user of the application a chance to merge some of his work with
            // fresh data... what you do here depends on your applications design.
            throw staleEx;
        } catch (Throwable ex) {
            // Rollback only
            ex.printStackTrace();
            try {
                if (sf.getCurrentSession().getTransaction().isActive()) {
                    log.debug("Trying to rollback database transaction after exception");
                    sf.getCurrentSession().getTransaction().rollback();
                }
            } catch (Throwable rbEx) {
                log.error("Could not rollback transaction after exception!", rbEx);
            }

            // Let others handle it... maybe another interceptor for exceptions?
            throw new ServletException(ex);
        }
    }

    public void init(FilterConfig filterConfig) throws ServletException {
        log.debug("Initializing filter, obtaining Hibernate SessionFactory from HibernateUtil");
        sf = HibernateUtil.getSessionFactory();
    }

    public void destroy() {}

}


Does that answer your question?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 2:00 pm 
Newbie

Joined: Thu Mar 02, 2006 7:47 pm
Posts: 8
jt_1000 wrote:
are you saving at application level session and/or sessionfactory? if not at what level are you saving them? Are you using 2nd level caching?


Also I am not using a cache yet.
Here is my config file

Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
      "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
      "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory name="java:/hibernate/RMADHibernateFactory">
        <property name="hibernate.connection.datasource">java:comp/env/jdbc/rmadPool</property>
        <property name="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</property>
        <property name="show_sql">true</property>
        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>

        <!-- Disable the second-level cache  -->
        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

    </session-factory>
</hibernate-configuration>


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 2:35 pm 
Expert
Expert

Joined: Mon Jan 09, 2006 5:01 pm
Posts: 311
Location: Sacramento, CA
doesn't look like you are closing your "session" on each request. It should be closed and restarted (or you can disconnect/clear and reconnect, if you feel you need to keep the session around...). A session is a "unit of work" for a particular web request.

_________________
-JT

If you find my replies helpful, please rate by clicking 'Y' on them. I appreciate it.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 2:42 pm 
Newbie

Joined: Thu Mar 02, 2006 7:47 pm
Posts: 8
Found the problem

It was related to versioning. The web app wasn't sending the correct version back so the app saw it as an insert. Thanks for all your help!! I'll give you a credit


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 2:50 pm 
Expert
Expert

Joined: Mon Jan 09, 2006 5:01 pm
Posts: 311
Location: Sacramento, CA
are you sure?As far as I know, the version should only identify if the object is out of date - not if it is a new one. Also you may check to make sure your equals() and hashCode() methods are working properly on the object.

_________________
-JT

If you find my replies helpful, please rate by clicking 'Y' on them. I appreciate it.


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