I having a GSP when it is accessed by two or more user at same time, It will throw
Row was updated or deleted by another transaction
Is there any way to share the render safely
Note: There is no update or save operation while rendering
Dude ,Have you tired on the action who updates ,list and read or connected with the row can be
#Transactional or do some concurrencyStuff exception handling
//Assume your domains are implemented just like or to be like this
class Author {
String name
Integer age
static hasMany = [books: Book]
}
//option one in your controllers or service class
Author.withTransaction { status ->
new Author(name: "Stephen King", age: 40).save()
status.setRollbackOnly()
}
Author.withTransaction { status ->
new Author(name: "Stephen King", age: 40).save()
}
//or
#Transactionl
def AuthorController () {
[list:list]
}
//or define a service like this
import org.springframework.transaction.annotation.Transactional
class BookService {
#Transactional(readOnly = true)
def listBooks() {
Book.list()
}
#Transactional
def updateBook() {
// …
}
def deleteBook() {
// …
}
}
for more visit : I hope this will be a bit useful ,Buddy!
Related
I have the two domain clases:
class Persona {
String nombre
String apellidos
static hasMany = [pertenencias: Pertenencia]
static constraints = {
}
static mapping = {
pertenencias cascade: "all-delete-orphan"
}
}
class Pertenencia {
String nombre
static belongsTo = [persona:Persona]
static constraints = {
}
}
The service:
class MembresiaService {
#Transactional
def saveAll() {
def p = new Persona(nombre: 'carlos', apellidos: 'gm')
p.addToPertenencias(nombre: 'auto')
p.addToPertenencias(nombre: 'computadora')
p.addToPertenencias(nombre: 'casa')
p.save()
}
#Transactional
def deletePertenencias() {
def p = Persona.get(1)
p.pertenencias?.clear()
}
}
And the controller:
class TestController {
def membresiaService
def index() {}
def saveAll() {
membresiaService.saveAll()
redirect(action: "index")
}
def deletePertenencias() {
membresiaService.deletePertenencias()
redirect(action: "index")
}
}
When I execute saveAll() method from controller it saves the data in the database, when I execute deletePertenencias() from controller it deletes the "pertenecias" collection of Persona from the database (as expected).
I have installed the Grails console plugin , first time I execute the lines of saveAll() service method in the console, the result is the "persona" and its "pertenencias" in database. Then I execute the lines of deletePertenencias() service method in console but it doesn't delete the data of database and the "persona" object mantains the "pertenencias" (as if I had not run deletePertenencias() code).
Anyone kwnow why the code executed from console gives unexpected results?
I expect the result was the same from controller and console but the behaviour is different.
I have a Grails project with multiple Domain Classes, and I want to make a persistence service as reusable as possible by only having one save() inside of it. To try and achieve this I have done the following in my project.
//PersistenceService.groovy
#Transactional
class PersistenceService {
def create(Object object) {
object.save flush: true
object
}
//BaseRestfulController
class BaseRestfulController extends RestfulController {
def persistenceService
def save(Object object) {
persistenceService.create(object)
}
//BookController
class BookController extends BaseRestfulController {
private static final log = LogFactory.getLog(this)
static responseFormats = ['json', 'xml']
BookController() {
super(Book)
}
#Transactional
def save(Book book) {
log.debug("creating book")
super.save(book)
}
So basically I have a bunch of domains for example Author etc, each with their own controller similar to the bookController. So is there a way to reuse the service for persistence like I am trying above?
Thank you
I'm doing something similar, but mainly because all my entities are not actually removed from the database but rather "marked" as removed. For several apps you need such an approach since it's critical to prevent any kind of data loss.
Since most databases do not provide support for this scenario, you can't rely on foreign keys to remove dependent domain instances when removing a parent one.
So I have a base service class called GenericDomainService which has methods to save, delete (mark), undelete (unmark).
This service provides a basic implementation which can be applied to any domain.
class GenericDomainService {
def save( instance ) {
if( !instance || instance.hasErrors() || !instance.save( flush: true ) ) {
instance.errors.allErrors.each {
if( it instanceof org.springframework.validation.FieldError ) {
log.error "${it.objectName}.${it.field}: ${it.code} (${it.rejectedValue})"
}
else {
log.error it
}
}
return null
}
else {
return instance
}
}
def delete( instance, date = new Date() ) {
instance.dateDisabled = date
instance.save( validate: false, flush: true )
return null
}
def undelete( instance ) {
instance.dateDisabled = null
instance.save( validate: false, flush: true )
return null
}
}
Then, in my controller template I always declare two services: the generic plus the concrete (which may not exist):
def ${domainClass.propertyName}Service
def genericDomainService
Which would translate for a domain called Book into:
def bookService
def genericDomainService
Within the controller methods I use the service like:
def service = bookService ?: genericDomainService
service.save( instance )
Finally, the service for a given domain will inherit from this one providing (if needed) the custom logic for these actions:
class BookService extends GenericDomainService {
def delete( instance, date = new Date() ) {
BookReview.executeUpdate( "update BookReview b set b.dateDisabled = :date where b.book.id = :bookId and b.dateDisabled is null", [ date: date, bookId: instance.id ] )
super.delete( instance, date )
}
def undelete( instance ) {
BookReview.executeUpdate( "update BookReview b set b.dateDisabled = null where b.dateDisabled = :date and b.book.id = :bookId", [ date: instance.dateDisabled, bookId: instance.id ] )
super.undelete( instance )
}
}
Hope that helps.
I am trying to run the sample Collab-Todo application as in book Beginning Groovy and Grails,page no.123 (Author:Christopher M. Judd,Joseph Faisal Nusairat,and James Shingler Publication:Apress and Edition:2008). Here is my User.groovy file:
package collab.todo
class User {
String userName
String firstName
String lastName
static hasMany = [todos: Todo, categories: Category]
static constraints = {
userName(blank:false,unique:true)
firstName(blank:false)
lastName(blank:false)
}
String toString () {
"$lastName, $firstName"
}
}
The UserController.groovy is as Follows:
package collab.todo
class UserController {
def scaffold = User
def login = {
}
def handleLogin = {
def user = User.findByUserName(params.userName)
if (!user) {
flash.message = "User not found for userName: ${params.userName}"
redirect(action:'login')
}
session.user = user
redirect(controller:'todo')
}
def logout = {
if(session.user) {
session.user = null
redirect(action:'login')
}
}
}
I am able to create,read,update or delete the User table as usual.Here is a sample screenshot of my User view:
In the scaffolding view, I am trying to show the list of all the users in a drop-down(as per the book) using following snippet inside the user/login.gsp:
<g:select name='userName' from="${User?.list()}"
optionKey="userName" optionValue="userName"></g:select>
But what I am getting in the login page is a dropdown with no values populated:
Here is the screenshot of the login page:
In case I change
from="${User?.list()}"
to
from="${User.list()}"
I am getting a NullPointerException. So any clues what is going on?
It looks like the User class could not be found from your view.
Try one of the following:
Add the import statement to your view.
<%# page import="collab.todo.User" %>
Or use the fully qualified name within from attribute.
from="${collab.todo.User.list()}"
The best practice would be to pass the list of users from the controller:
def login = {
[users: User.list()]
}
And use the collection within your view
from="${users}"
I'm attempting to create a geb module that represents an unordered list of elements. I've seen examples for how to do this with tables but I'm having a hard time translating that to UL->LI elements. Here's what I have so far:
class CheckoutPage extends Page {
static content = {
cartItemList { $(".cart_items ul") }
cartItem { i -> module CartItem, cartItems[i] }
cartItems(required: false) { cartItemList.find("li.item") }
}
}
class CartItem extends Module {
static content = {
thumbnail { $("img.book_cover", it) }
itemInfo { $("div.item_info", it) }
bookTitle { itemInfo.find("h1").find("a").text() }
}
}
When I do the following in my spec:
def "add an item to the cart"() {
when:
to CheckoutPage, productId: "10001"
then:
cartItems.size() == 1
def cartItem = cartItems(0)
cartItem.bookTitle == "Test Book Title 001"
}
I get the following error:
geb.error.UnresolvablePropertyException: Unable to resolve bookTitle
as content for cartItems
However, cartItem is a DOM element because I can do this and it works:
cartItem.find("div.item_info").find("h1").find("a").text() == "Test Book Title 001"
You may want to check out this blog post. It outlines almost exactly what you're looking for.
http://adhockery.blogspot.com/2010/11/modelling-repeating-structures-with-geb.html
After looking through that blog post, this is what I came up with for your page class:
class CheckoutPage extends Page {
static content = {
cartItemList { $(".cart_items ul") }
cartItems(required: false) {
cartItemList.find("li.item").collect { item->
module(CartItem, item)
}
}
}
}
Then your module should look like this:
class CartItem extends Module {
static content = {
thumbnail { $("img.book_cover") }
itemInfo { $("div.item_info") }
bookTitle { itemInfo.find("h1").find("a").text() }
}
}
It looks like you have a bug in your code - you probably wanted to say def cartItem = cartItem(0) not def cartItem = cartItems(0). Also, try to avoid using the same names for local variables and your content definitions (like you do for cartItem) as it sometimes leads to name clashes which are pretty hard to track down.
You could simplify your content definition by using moduleList() method
static content = {
cartItemList { $(".cart_items ul") }
cartItems { i -> moduleList CartItem, cartItemList.find("li.item"), i }
}
and in your test:
then:
cartItems.size() == 1 //here you use it to retrieve the full list
def item = cartItems(0) //here you use it to retrieve a single element
item.bookTitle == "Test Book Title 001"
The answer to this question was a combination of both answers given. I needed those answers to better understand what was happening. This is the actual solution:
class CheckoutPage extends Page {
static content = {
cartItemList { $(".cart_items ul") }
cartItems(required: false) { module CartItem, cartItemList.find("li.item")}
}
}
class CartItem extends Module {
static content = {
thumbnail { $("img.book_cover") }
itemInfo { $("div.item_info") }
bookTitle { itemInfo.find("h1").find("a").text() }
}
}
And the test:
def "add an item to the cart"() {
when:
to CheckoutPage, productId: '10001'
then:
cartItems.size() == 1
def cartItem = cartItems(0)
cartItem.bookTitle == "Test Book Title 001"
}
The reasons (I think) this works is because we're dealing with individual LI elements. Not a container like a TR with several TD elements. So the context here is the LI and by using module instead of moduleList, I am only dealing with the individual LI element, and not a list of them. The cartItems contains the LI elements as a List already.
At least, that is how I understand it and it is working.
How can I work around http://jira.grails.org/browse/GPJODATIME-28 which prevents a domain class from having a hasMany of any extended type?
I'm thinking of switching the whole app to persisting a custom UserType derived from BigDecimal for posix epoch dates. Seem's like a hammer for a walnut though. IS there another approach I could take?
import org.joda.time.Instant
class Foo {
Instant birthday
Set favoriteDays = []
static hasMany = [
favoriteDays : Instant
]
static constraints = {
}
}
Hopefully I'm not missing something in your question but I've done things like this:
Create a class called MyInstant and use it in the hasMany
import org.joda.time.Instant
class MyInstant {
Instant myInstant
//anything else you might need
}
class Foo {
MyInstant birthday
Set favoriteDays = []
static hasMany = [favoriteDays: MyInstant]
}
I've tested this in the FooController:
import org.joda.time.Instant
class FooController {
def save() {
def fooInstance = new Foo(params)
.addToFavoriteDays(new MyInstant(myInstant: new Instant()))
.addToFavoriteDays(new MyInstant(myInstant: new Instant()))
.addToFavoriteDays(new MyInstant(myInstant: new Instant()))
if (!fooInstance.save(flush: true)) {
render(view: "create", model: [fooInstance: fooInstance])
return
}
flash.message = message(code: 'default.created.message', args: [message(code: 'foo.label', default: Foo'), fooInstance.id])
redirect(action: "show", id: fooInstance.id)
}
}
Everything saves correctly and the show action then shows the new Foo with all the instants. I've tested this on H2 and MySql.