Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grails one-many mapping stalestaleexception on composite key

I use grails 2.0.0. I have three objects Member, Product and ProductType. Member has many Products and is a one-to-many relation. Product points to ProductType (reference table) and is a many-to-one relation. My question is about deleting Products. It works in one scenario and not in another. Read on.

Rough outline of the mappings below:

Member.groovy:

class Member  {
   Long id
   ....
   SortedSet products
   static hasMany = [products:Product]
   static mapping = {
        table 'T_MEMBER'
        id column:'MEMBER_ID'...
       products cascade: "all-delete-orphan"
   }
}

Product.groovy:

class Product {
   Long id
   ProductType productType
   ...
   static belongsTo = [member:Member]
   static mapping = {
        table 'T_PRODUCT'
        id column:'PRODUCT_ID'
        member column: 'MEMBER_ID'
        productType column: 'PRODUCT_TYPE'
        ...
   }
}

ProductType.groovy:

class ProductType {
   Long id
   ..
   static mapping = {
        table 'T_PRODUCT_TYPE'
        id column:'PRODUCT_TYPE', generator:'assigned'
    ...
   }
}

I got the client service code an outline of which is ...

    if((newMember.products) && (newMember.products.size() >0)) {
        def addList = newMember.products - existingMember.products
        def removeList = existingMember.products- newMember.products
        removeList.each { product ->
            existingMember.removeFromProducts(product)
        }
        addList.each {product ->
            existingMember.addToProducts(product)
        }
    }

So far so good. This is working perfectly. However when I introduce composite primary key for the T_PRODUCT table by doing the following:

   static mapping = {
        table 'T_PRODUCT'
        //id column:'PRODUCT_ID'
        id composite:['member', 'productType']
        member column: 'MEMBER_ID'
        productType column: 'PRODUCT_TYPE'
        ...
   }

I get this:

org.hibernate.StaleStateException: Batch upda Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1 org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1 at ProductService.cleanUpGorm(ProductService.groovy:442) at ProductService.maintainProduct(ProductService.groovy:213) at ClientService$_maintainMembers_closure5.doCall(ClientService.groovy:158) at ClientService.maintainMembers(ClientService.groovy:152) at ClientService.processMembers(ClientService.groovy:394)

Any idea where I might be going wrong?

like image 276
arrehman Avatar asked May 02 '12 23:05

arrehman


2 Answers

Your Product domain class must implements Serializable and override methods hashCode() and equals(), this thing must be done in situations where you use composite key.

Your Product domain class must be like this

class Product implements Serializable {
        Long id
        ProductType productType
        ...

        static mapping = {
             table 'T_PRODUCT'
             id composite:['member', 'productType']
             member column: 'MEMBER_ID'
             productType column: 'PRODUCT_TYPE'
        }

        boolean equals(other) {
            if (!(other instanceof Product )) {
                return false
            }
            other.member== member && other.productType== productType
        }

        int hashCode() {
            def builder = new HashCodeBuilder()
            builder.append member
            builder.append productType
            builder.toHashCode()
        }

    }

I think this way everything will be OK.

In case of problems write.

like image 200
Karen Avatar answered Sep 26 '22 00:09

Karen


I strongly recommend reading the Grails doc, 5.5.2.5 Composite Primary Keys. They do point out the following, which you did not respect:

  1. Domain classes mapped with composite primary keys must implement the Serializable interface and override the equals() and hashCode() methods, using the properties in the composite key for the calculations.
  2. You also need to be aware of using composite primary keys is associations, especially the mapped column names.
  3. May be, it is not that good using a many-to-one mapped type in a composite key.

Maybe it help you getting the right direction.

like image 30
micfra Avatar answered Sep 23 '22 00:09

micfra