I am having difficulty removing a child from an association. I'm using Grails 4.0.3. The two classes in question are the following:
ShoppingCart:
class ShoppingCart implements Serializable {
private static final long serialVersionUID = 1
long id //don't think this is needed since I have a composite id below
User user
Store store
SortedSet<ShoppingCartItem> items
static hasMany = [items: ShoppingCartItem]
static constraints = {
user nullable: false
store nullable: false
}
static mapping = {
id composite: ['user', 'store']
items cascade: "all-delete-orphan"
}
}
And ShoppingCartItem:
class ShoppingCartItem implements Comparable<ShoppingCartItem>, Serializable {
private static final long serialVersionUID = 1
long id //don't think this is needed since I have a composite id below
static belongsTo = [shoppingCart: ShoppingCart]
Product product
int quantity = 0
BigDecimal purchasePrice
Date lastItemAdded
static constraints = {
product nullable: false
purchasePrice nullable: false
lastItemAdded nullable: false
}
static mapping = {
id composite: ['shoppingCart', 'product']
}
int compareTo(ShoppingCartItem otherItem) {
lastItemAdded.compareTo(otherItem.lastItemAdded)
}
}
Because I have a bidirectional relationship (using the belongsTo in ShoppingCartItem) and the ShoppingCart has a composite key, my shopping_cart_item table looks like the following:
'shopping_cart_user_id', 'bigint(20)', 'NO', 'PRI', '', ''
'shopping_cart_store_id', 'bigint(20)', 'NO', 'PRI', '', ''
'product_id', 'bigint(20)', 'NO', 'PRI', '', ''
'version', 'bigint(20)', 'NO', '', '', ''
'date_created', 'datetime', 'NO', '', '', ''
'last_updated', 'datetime', 'NO', '', '', ''
'quantity', 'int(11)', 'NO', '', '', ''
'purchase_price', 'decimal(19,2)', 'NO', '', '', ''
'last_item_added', 'datetime', 'NO', '', '', ''
I am having a heck of time trying to delete a shopping cart item. I have read through https://spring.io/blog/2010/07/02/gorm-gotchas-part-2/ several times and it makes sense to me, but I have not been successful.
In a grails service method I'm doing the following:
def updateCountInCartForProduct(ShoppingCart cart, Serializable productId, int newQuantity) {
def product = productService.get(productId)
def cartItem = cart.items.find { it.product == product }
if ( cartItem ) {
if ( newQuantity == 0 ) {
cart.removeFromItems(cartItem) // <-- this line throws the error
} else {
cartItem.quantity = newQuantity
cartItem.save()
}
}
}
After executing this method I get the following error:
12/22/2020 07:48:00 - ERROR [org.hibernate.internal.ExceptionMapperStandardImpl]: HHH000346: Error during managed flush [Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1]
12/22/2020 07:48:01 - ERROR [org.grails.web.errors.GrailsExceptionResolver]: StaleStateException occurred when processing request: [POST] /shop/updateCartQuantity - parameters:
productId: 7
newQuantity: 0
Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1. Stacktrace follows:
java.lang.reflect.InvocationTargetException: null
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
After turning on SQL logging I am seeing something that seems strange to me:
12/22/2020 07:48:00 - DEBUG [org.hibernate.SQL]: delete from shopping_cart_item where shopping_cart_user_id=? and shopping_cart_store_id=? and product_id=? and version=?
12/22/2020 07:48:00 - TRACE [org.hibernate.type.descriptor.sql.BasicBinder]: binding parameter [1] as [BIGINT] - [null]
12/22/2020 07:48:00 - TRACE [org.hibernate.type.descriptor.sql.BasicBinder]: binding parameter [2] as [BIGINT] - [null]
12/22/2020 07:48:00 - TRACE [org.hibernate.type.descriptor.sql.BasicBinder]: binding parameter [3] as [BIGINT] - [7]
12/22/2020 07:48:00 - TRACE [org.hibernate.type.descriptor.sql.BasicBinder]: binding parameter [4] as [BIGINT] - [1]
Notice the binding parameters for shopping_cart_user_id and shopping_cart_store_id are null. I don't know if this is causing my problem, but it seems suspect. When I debug through the code, the cartItem being removed does have a reference to the parentShopping cart and none of the ids on any of the objects are null, so I don't know where those nulls are coming from.
Any ideas?