Wednesday, March 7, 2012

Cryptic ColdFusion ORM Hibernate Error

Troubleshooting an old Adobe ColdFusion 9 application of mine today and was getting this error message:
HIBERNATE ERROR - Exception executing batch:
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
Now I also saw an error about a foreign key at one point, but who knows why. The issue was being caused during a value update. The goal is to allow the user to create a new object of type Domain inline. It's simple really, they just enter the Domain text and on the back end I make sure the Domain doesn't already exist before creating the domain and adding it to its parent entity (which they are editing at the time).

Here is the snippet of code that checks to see if the domain already exists, and creates the object if it does not:
// try to load the domain by the passed name
var domain = entityLoad("Domain", {name=arguments.value, project = o.getProject()}, true);
// if it doesn't exist, we need to create a new domain for this project
if ( NOT structKeyExists(local, 'domain') ) {
  domain = entityNew('Domain');
  domain.setName(arguments.value);
  domain.setProject(o.getProject());
  entitySave(domain);
}
o.setDomain(domain);
So what is happening above is we try to load the Domain, if it doesn't exist we create it, set the bi-di relationship to the project and then save it. The Domain is then added to the parent object. When the error is thrown no line number is given (cryptic, remember). So the most curious thing was I had another object type that was working fine. I compared them, and saw the error in my ways. Here is the offending object:
<cfcomponent persistent="true" table="sel_domain"  output="false" entityName='Domain'>
  <!---- properties ---->
  
  <cfproperty name="id" column="id" type="numeric" ormtype="int" fieldtype="id" generator="increment" /> 
  <cfproperty name="name" column="domain" type="string" ormtype="string"  /> 
  <cfproperty name="color" column="color" type="string" ormtype="string" default="" />
  <cfproperty name="project" cfc="com.Project" fkcolumn="projectID" fieldtype="many-to-one" />
  <cfproperty name="entities" singularname="entity" fieldtype="one-to-many" cfc="com.Entity" fkcolumn="domainid"/>  

  <cffunction name="init" returntype="Domain" access="public" output="false" hint="Constructor">
    
    <cfscript>
      setID(-1);
      
    </cfscript>
    
    <cfreturn this />
  </cffunction>
</cfcomponent> 
Can anyone guess what the issue is? If not, don't feel bad. Took me about 20 minutes to figure it out with the stack trace in front of me. I forgot to add the unsavedvalue="-1" to the id field. This can be fixed by adding that attribute, or in the case of the working object, simply removing the init() function.

The moral is that the error can be thrown when we are trying to save a disconnected object with ColdFusion ORM's entitySave() that already exists in our persistence layer. Hopefully this helps someone else make some sense of their issue!

1 comment:

  1. First thought was wrap your if in a transaction ...

    ReplyDelete