-->
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: Updates of session loaded objects not being detected
PostPosted: Fri Sep 16, 2005 11:45 am 
Beginner
Beginner

Joined: Wed Nov 05, 2003 4:38 pm
Posts: 29
I'm not sure if I've missed something really small and stupid but the example in the documentation is pretty straightforward on how to update an object that has been loaded into the current session. Try as I may I am unable to get the following code to generate the update SQL, it seems the object isn't detected as being dirty despite having called many of it's setters. The insert code path works fine. The list of eligibility objects it's processing was generated from a text file and all of them have 0 for their ID. They are being used as is on insert but their state is copied into a loaded object if it exists (the load succeeds) which according to the documentation should make it dirty and be automatically updated when session.flush() is called or the transaction is commited (I'm only commiting the transaction). So either I've missed something in the manual that covers this particular case or I've found an annoying bug.

Hibernate version:
Version 3.0.3

Mapping documents:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
   <class name="com.pristx.Eligibility" table="eligibility">
      <id name="eligibilityId" column="eligibility_id" type="integer">
         <generator class="native"/>
      </id>
      <version name="version" column="version" type="integer"/>
      <property name="processDate" column="process_date" type="timestamp"/>
      <property name="employeeId" column="employee_id" type="integer"/>
      <property name="employeeName" column="employee_name" type="string"/>
      <property name="nameSuffix" column="name_suffix" type="string"/>
      <property name="address1" column="address_1" type="string"/>
      <property name="address2" column="address_2" type="string"/>
      <property name="city" column="city" type="string"/>
      <property name="state" column="state" type="string"/>
      <property name="zipCode" column="zip_code" type="string"/>
      <property name="country" column="country" type="string"/>
      <property name="phone" column="phone" type="string"/>
      <property name="gender" column="gender" type="string"/>
      <property name="birthDate" column="birth_date" type="timestamp"/>
      <property name="maritalStatus" column="marital_status" type="string"/>
      <property name="educationLevel" column="education_level" type="string"/>
      <property name="employeeType" column="employee_type" type="string"/>
      <property name="departmentName" column="department_name" type="string"/>
      <property name="jobCode" column="job_code" type="string"/>
      <property name="jobDescription" column="job_description" type="string"/>
      <property name="fullPartTime" column="full_part_time" type="string"/>
      <property name="hireDate" column="hire_date" type="timestamp"/>
      <property name="rehireDate" column="rehire_date" type="timestamp"/>
      <property name="employeeStatus" column="employee_status" type="string"/>
      <property name="effectiveDate" column="effective_date" type="timestamp"/>
      <property name="terminationDate" column="termination_date" type="timestamp"/>
      <property name="lastDateWorked" column="last_date_worked" type="timestamp"/>
      <property name="standardHours" column="standard_hours" type="java.math.BigDecimal"/>
      <property name="averageWeek" column="average_week" type="java.math.BigDecimal"/>
      <property name="averageDay" column="average_day" type="java.math.BigDecimal"/>
      <property name="daysPerWeek" column="days_per_week" type="integer"/>
      <property name="supervisorName" column="supervisor_name" type="string"/>
      <property name="locationCode" column="location_code" type="string"/>
   </class>
</hibernate-mapping>


Code between sessionFactory.openSession() and session.close():
Code:
public void save() {
   Transaction transaction = new Transaction();
      
   try {
      transaction.execute(new InsertOrUpdateEligibilityListCommand(list));
   } catch (Exception e) {
      e.printStackTrace();
   }
}


public class Transaction {
   public void execute(Command command) throws Exception {
      Session session = SessionManager.openSession();
      Transaction transaction = null;
      
      try {
         transaction = session.beginTransaction();
         command.execute();
         transaction.commit();
      } catch (Exception e) {
         if (transaction != null) {
            transaction.rollback();
         }
         
         throw e;
      } finally {
         SessionManager.closeSession();
      }
      
      command.success();
   }
}

public class InsertOrUpdateEligibilityListCommand implements Command {
   private List<Eligibility> eligibilityList;
   
   public InsertOrUpdateEligibilityListCommand(List<Eligibility> eligibilityList) {
      this.eligibilityList = eligibilityList;
   }

   public void execute() throws Exception {
      for (Eligibility eligibility : eligibilityList) {
         Eligibility existing = EligibilityDAO.findEligibility(eligibility.getEmployeeId());
         
         if (existing == null) {
            eligibility = EligibilityDAO.insertEligibility(eligibility);
         } else {
            existing.setAddress1(eligibility.getAddress1());
            existing.setAddress2(eligibility.getAddress2());
            existing.setAverageDay(eligibility.getAverageDay());
            existing.setAverageWeek(eligibility.getAverageWeek());
            existing.setBirthDate(eligibility.getBirthDate());
            existing.setCity(eligibility.getCity());
            existing.setCountry(eligibility.getCountry());
            existing.setDaysPerWeek(eligibility.getDaysPerWeek());
            existing.setDepartmentName(eligibility.getDepartmentName());
            existing.setEducationLevel(eligibility.getEducationLevel());
            existing.setEffectiveDate(eligibility.getEffectiveDate());
            existing.setEmployeeId(eligibility.getEmployeeId());
            existing.setEmployeeName(eligibility.getEmployeeName());
            existing.setEmployeeStatus(eligibility.getEmployeeStatus());
            existing.setEmployeeType(eligibility.getEmployeeType());
            existing.setFullPartTime(eligibility.getFullPartTime());
            existing.setGender(eligibility.getGender());
            existing.setHireDate(eligibility.getHireDate());
            existing.setJobCode(eligibility.getJobCode());
            existing.setJobDescription(eligibility.getJobDescription());
            existing.setLastDateWorked(eligibility.getLastDateWorked());
            existing.setLocationCode(eligibility.getLocationCode());
            existing.setMaritalStatus(eligibility.getMaritalStatus());
            existing.setNameSuffix(eligibility.getNameSuffix());
            existing.setPhone(eligibility.getPhone());
            existing.setProcessDate(eligibility.getProcessDate());
            existing.setRehireDate(eligibility.getRehireDate());
            existing.setStandardHours(eligibility.getStandardHours());
            existing.setState(eligibility.getState());
            existing.setSupervisorName(eligibility.getSupervisorName());
            existing.setTerminationDate(eligibility.getTerminationDate());
            existing.setZipCode(eligibility.getZipCode());
         }
      }
   }

   public void success() throws Exception {
      // Do nothing
   }
}

public class EligibilityDAO {
   private static EligibilityDAO instance = new EligibilityDAO();
   
   public static Eligibility findEligibility(int employeeId) {
      return instance.find(employeeId);
   }
   
   public static Eligibility insertEligibility(Eligibility eligibility) {
      return instance.insert(eligibility);
   }
   
   public EligibilityDAO() {
      super();
   }
   
   public Eligibility find(int employeeId) {
      Session session = SessionManager.openSession();
      Query query = session.createQuery("FROM Eligibility AS e WHERE e.employeeId = :employeeId");
      query.setInteger("employeeId", employeeId);
      
      return (Eligibility)query.uniqueResult();
   }
   
   public Eligibility insert(Eligibility eligibility) {
      Session session = SessionManager.openSession();
      eligibility.setEligibilityId((Integer)session.save(eligibility));
      
      return eligibility;
   }
}

public class SessionManager {
   private SessionFactory sessionFactory;
   private Session session;
   
   public static void initialize() {
      instance = new SessionManager();
   }
   
   public SessionManager() {
      sessionFactory = createConfiguration().buildSessionFactory();
      session = null;
   }
   
   public static SessionManager getInstance() {
      return instance;
   }
   
   public Session openCurrentSession() {
      if (session == null) {
         session = sessionFactory.openSession();
      }
      
      return session;
   }
   
   public void closeCurrentSession() {
      if (session != null) {
         session.close();
         session = null;
      }
   }

   private static final String MAPPING_FILE_LOCATION = "com/pristx/dao/";
   private static SessionManager instance;
   
   public static Session openSession() {
      return instance.openCurrentSession();
   }

   public static void closeSession() {
      instance.closeCurrentSession();
   }
   
   private static Configuration createConfiguration() {
      Configuration configuration = new Configuration();
      InputStream input = SessionManager.class.getResourceAsStream("hibernate.properties");
      Properties properties = new Properties();
      
      try {
         properties.load(input);
      } catch (IOException e) {
         e.printStackTrace();
         System.exit(0);
      }
      
      configuration.setProperties(properties);
      configuration.addResource(MAPPING_FILE_LOCATION + "Eligibility.hbm.xml");
      configuration.addResource(MAPPING_FILE_LOCATION + "File.hbm.xml");
      configuration.addResource(MAPPING_FILE_LOCATION + "Payroll.hbm.xml");
      configuration.addResource(MAPPING_FILE_LOCATION + "User.hbm.xml");
      
      return configuration;
   }
}


Full stack trace of any exception that occurs:
No exceptions

Name and version of the database you are using:
Microsoft SQL Server 2000

The generated SQL (show_sql=true):
N/A

Debug level Hibernate log excerpt:
N/A
Code:


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 16, 2005 12:43 pm 
Expert
Expert

Joined: Wed Apr 06, 2005 5:03 pm
Posts: 273
Location: Salt Lake City, Utah, USA
It's because you are starting the transaction in one session (in Transaction.Execute()), but using a separate session to load the object (EligibilityDAO.find()). The object needs to be loaded using the same session your transaction is running on.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 16, 2005 1:35 pm 
Beginner
Beginner

Joined: Wed Nov 05, 2003 4:38 pm
Posts: 29
They are both using the same session. To be safe I just verified that sessionFactor.openSession() is only called once in the entire execution of the program.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 16, 2005 1:45 pm 
Contributor
Contributor

Joined: Thu Nov 06, 2003 9:49 pm
Posts: 104
Location: New York, NY
Nathanmoon is right.

Transaction.execute() doesn't really meet your needs. What you should be doing is managing your Hibernate session so that it *spans* multiple calls to DAOs. Try using a thread local or JTA transaction local session manager.

Think of a Hibernate session as a graph of objects that you want to work with. When you close the session, all the objects are no longer managed by the session. If your code still references them, well... they're just ordinary Java objects at that point. They can be used by Java code if they aren't proxies, but Hibernate won't update the database if they change.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 16, 2005 2:13 pm 
Beginner
Beginner

Joined: Wed Nov 05, 2003 4:38 pm
Posts: 29
As mentioned in my previous post only one session is generated during the entire execution of the program. I verified this by setting a break point on the session = sessionFactory.openSession() line.

Also I am using a session manager class (it's posted in my first post). Instead of using ThreadLocal storage I am using a simple instance variable instead. This is because it will always be called from a single thread since it's a simple read in file and import to database program and I do not need to make sure that each of my threads need their own session because there will always be only one thread.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 16, 2005 2:29 pm 
Expert
Expert

Joined: Wed Apr 06, 2005 5:03 pm
Posts: 273
Location: Salt Lake City, Utah, USA
Sorry, I didn't look at the code close enough. The session part looks ok. I'm not sure what the problem is (I'm pretty sure it's not a Hibernate bug, though; not on something this simple).

One thing that's interesting is that in your Transaction class you are using a hibernate Transaction (same class name, not fully qualified). Seems like this shouldn't compile...


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 16, 2005 2:47 pm 
Beginner
Beginner

Joined: Wed Nov 05, 2003 4:38 pm
Posts: 29
Most of these classes actually have a 3 character prefix that I removed before posting. I removed all of them because they are part of a clients name and didn't want that out on the internet.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 16, 2005 2:50 pm 
Beginner
Beginner

Joined: Wed Nov 05, 2003 4:38 pm
Posts: 29
The only lead I have in this problem is that in all the examples I find on automatic dirty checking they use session.load() to get the instance to modify while I'm using query.uniqueResult(). I have been unable to find a reason why these would be treated differently just yet.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 16, 2005 3:55 pm 
Contributor
Contributor

Joined: Thu Nov 06, 2003 9:49 pm
Posts: 104
Location: New York, NY
Sorry, I was thrown off by the one line static methods that invoke non-static methods with almost the same name (a pet peve of mine... sorry!). ;)

As long as you've got the session managed properly (i.e. you don't close it before you update the object), the dirty checking will occur on any object managed by the session, regardless of how it got there (e.g. load, HQL query, etc.). If your code sets the properties of the object after it is loaded, but before the commit, then the dirty check will detect this and cause updates to be generated.

Try writing an Interceptor so you can see through what's happening during the commit.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 16, 2005 4:25 pm 
Beginner
Beginner

Joined: Wed Nov 05, 2003 4:38 pm
Posts: 29
OK I knew I was doing something stupid and I finally tracked down what it was. I was not paying attention to the data and an ID I was assuming to be correct was actually wrong and the imported file inserted a new record with the correct ID thereby not updating the incorrect one. This should be a law like in technical support were you always check if things are plugged in right before doing other troubleshooting. It should have also tipped me off that there are 78 records in the file but 79 in the data table. Boy do I know how to waste a day.


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.