Showing posts with label Grails on Groovy. Show all posts
Showing posts with label Grails on Groovy. Show all posts

Monday, August 28, 2023

Grails / GORM apply criteria query with hasmany String for filter

I have a domain object (User) like this:
class User {
   String name

   static hasMany = [
      permissions: String
   ]
}
And I am trying to query all the User with certain permissions. So I have to join and check permissions property. Here how we can do this -
User.withCriteria {
    createAlias('permissions', 'n') 
    ilike 'n.elements', '%permission_1%'
}
The trick is to use 'n.elements'

Friday, February 8, 2019

GRAILS > FUNCTIONALITY AFTER TRANSACTION COMMITTED

So the problem is when we working on grails project with hibernate transaction to manage data, we do not know when actually transaction committed or not. But sometimes we have to wait until current transaction finally committed. Because unless transaction committed, this data will not available for other transactions. Below is a sample project showing how to notified or when actually current transaction committed. Its some wired way but its working.

THIS PROJECT FOR DEMONSTRATE HOW TO DO SOME ADDITIONAL WORK AFTER AN TRANSACTION COMMITED

1. First setup DataSource.groovy
2. Add *mavenRepo "https://oauth.googlecode.com/svn/code/maven"* in *repositories* to BuildConfig.groovy
3. Add below dependencies to *dependencies* in BuildConfig.groovy
    compile "org.springframework:spring-orm:$springVersion"
    runtime 'mysql:mysql-connector-java:5.1.29'
    runtime 'org.springframework:spring-test:4.0.5.RELEASE'
4. Add a controller named *HomeController.groovy*
5. Add a service named *HomeService.groovy*
6. Add a domain named *Home.groovy*

MOST IMPORTANT PARTS:
7. Add below groovy files
named *org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTransactionManager.groovy*
named *org.codehaus.groovy.grails.orm.hibernate.TransactionStatus.groovy*
named *org.codehaus.groovy.grails.orm.support.GrailsTransactionTemplate.groovy*
under *src/groovy*

8. You are done! See *HomeService.groovy* to see how you can use this feature in Grails project.

package org.codehaus.groovy.grails.orm.hibernate

import groovy.transform.CompileDynamic
import org.hibernate.FlushMode
import org.springframework.orm.hibernate4.HibernateTransactionManager
import org.springframework.transaction.TransactionDefinition
import org.springframework.transaction.support.DefaultTransactionStatus

class GrailsHibernateTransactionManager extends HibernateTransactionManager {
    @Override
    protected void doBegin(Object transaction, TransactionDefinition definition) {
        super.doBegin transaction, definition
        if (definition.isReadOnly()) {
            setFlushModeManual(transaction)
        }
    }

    @CompileDynamic
    protected void setFlushModeManual(transaction) {
        transaction.sessionHolder?.session?.flushMode = FlushMode.MANUAL
    }

    @Override
    protected DefaultTransactionStatus newTransactionStatus(TransactionDefinition definition, Object transaction, boolean newTransaction, boolean newSynchronization, boolean debug, Object suspendedResources) {
        return new TransactionStatus(super.newTransactionStatus(definition, transaction, newTransaction, newSynchronization, debug, suspendedResources))
    }

    @Override
    protected void doCommit(DefaultTransactionStatus status) {
        super.doCommit(status)
        status.triggerCommitHandlers()
    }
}
BELOW IS SAMPLE OUTPUT

package com.pritom

import grails.transaction.Transactional
import org.codehaus.groovy.grails.orm.hibernate.TransactionStatus

@Transactional
class HomeService {
    void saveEntity() {
        TransactionStatus.current.onCommit {
            println("YES!!! TRANSACTION COMMITTED SUCCESSFULLY!!!")
            println("HOME COUNT ${Home.count()}")
        }
        Home home = new Home()
        home.name = "House #${Home.count() + 1}"
        home.addreess = "Lane ${Home.count() + 1}, Dhaka"
        home.save()
    }
}

2019-02-08 11:33:55,048 [http-bio-8080-exec-1] DEBUG hibernate.SQL  - select count(*) as y0_ from home this_
Hibernate: select count(*) as y0_ from home this_
2019-02-08 11:33:55,050 [http-bio-8080-exec-1] DEBUG hibernate.SQL  - select count(*) as y0_ from home this_
Hibernate: select count(*) as y0_ from home this_
2019-02-08 11:33:55,053 [http-bio-8080-exec-1] DEBUG hibernate.SQL  - insert into home (version, addreess, name) values (?, ?, ?)
Hibernate: insert into home (version, addreess, name) values (?, ?, ?)
2019-02-08 11:33:55,054 [http-bio-8080-exec-1] TRACE sql.BasicBinder  - binding parameter [1] as [BIGINT] - [0]
2019-02-08 11:33:55,054 [http-bio-8080-exec-1] TRACE sql.BasicBinder  - binding parameter [2] as [VARCHAR] - [Lane 5, Dhaka]
2019-02-08 11:33:55,054 [http-bio-8080-exec-1] TRACE sql.BasicBinder  - binding parameter [3] as [VARCHAR] - [House #5]
YES!!! TRANSACTION COMMITTED SUCCESSFULLY!!!
2019-02-08 11:33:55,130 [http-bio-8080-exec-1] DEBUG hibernate.SQL  - select count(*) as y0_ from home this_
Hibernate: select count(*) as y0_ from home this_
HOME COUNT 5
You can use multiple TransactionStatus.current.onCommit, each will be called one after one.
You can download sample project from here
GitHub project link
Required JAR file to get this working (if dependecny failed)

Saturday, April 21, 2018

Grails on Groovy > @Transactional does not rollback on checked exceptions

We’re using the Spring Framework in most of our grails applications to manage database transaction.
One of the big advantages is the the declarative transaction handling using the @Transactional attribute.
import org.springframework.transaction.Transactional;
 
@Transactional
public class MyService {
  List exec () {
    
  }
}
That simple annoation on class managed by a Spring ApplicationContext causes all method calls onto that service to be bound to a transaction. The transaction is committed after the method call has left the service again and it’s rollbacked for the case an exception is thrown
But be careful: Only unchecked exceptions (that is, subclasses of java.lang.RuntimeException) are rollbacked by default. For the case, a checked exception is thrown, the transaction will be committed!
And that customization can be done very easily by just adding the parameter rollBackFor to the @Transactional attribute:
import org.springframework.transaction.Transactional;
 
@Transactional(rollbackFor = Exception.class)
public class MyService {
  List exec () {
    
  }
}