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?
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.
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:
Serializable
interface and override the equals()
and hashCode()
methods, using the properties in the composite key for the calculations.Maybe it help you getting the right direction.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With