We frequently use createAlias to create alias between entity. It actually create connection based on foreign key and primary key between two entities. Below is a example how we create alias between entities: |
Table1.createCriteria().list { createAlias("scores", "scores") } |
Which will produce SQL like below where we can see that foreign key of table1 create a link with table2_child based on primary key id as following: |
select ... from table1 this_ inner join table2_child scores1_ on (this_.id=scores1_.table1_id) |
But if we need more on add to filter when joining them, yeah, we can do that. We can add extra conditions to on part of that SQL. To do so, first need to create a AliasBuiilder.groovy file like below: |
package com.gradle_app import org.hibernate.criterion.Criterion import org.hibernate.sql.JoinType abstract class AliasBuilder { static final Object synk0 = new Object() static Long number = 0L static void fixCriteriaBuilderProps(criteriaBuilder) { if (!criteriaBuilder.properties.containsKey("aliases")) { criteriaBuilder.metaClass.aliases = [:] criteriaBuilder.metaClass.data = [:] } criteriaBuilder = null } static String createAlias0(criteriaBuilder, String field, String aliasPath = field, JoinType joinType = JoinType.INNER_JOIN, Criterion customCriterion = null) { aliasPath = aliasPath ? aliasPath : field joinType = joinType ? joinType : JoinType.INNER_JOIN fixCriteriaBuilderProps(criteriaBuilder) def subCriteria = criteriaBuilder.criteria.subcriteriaList.find { it.path == aliasPath } if(subCriteria) { try { return subCriteria.alias } finally { criteriaBuilder = field = aliasPath = joinType = subCriteria = null } } else { String alias = "${field}_custom_name_${nextSerialNumber()}".toLowerCase() criteriaBuilder.createAlias(aliasPath, alias, joinType, customCriterion) String other = alias.substring(0, criteriaBuilder.sessionFactory.dialect.getMaxAliasLength()) + (criteriaBuilder.properties.aliases.size() + 1) + "_" criteriaBuilder.properties.aliases[alias] = other criteriaBuilder.properties.data[aliasPath] = alias try { return alias } finally { criteriaBuilder = field = aliasPath = joinType = subCriteria = alias = other = null } } } static String nextSerialNumber() { Long serial = null try { synchronized (synk0) { number = serial = number + 1L if (number == Long.MAX_VALUE) { number = 1L } } return serial.toString() } finally { serial } } } |
And another CustomCriteria.groovy file like this: package com.gradle_app import org.hibernate.Criteria import org.hibernate.HibernateException import org.hibernate.criterion.CriteriaQuery import org.hibernate.criterion.Criterion import org.hibernate.engine.spi.TypedValue import org.hibernate.internal.util.StringHelper class CustomCriteria implements Criterion { private static final TypedValue[] NO_VALUES = new TypedValue[0] public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException { String alias = criteriaQuery.getSQLAlias(criteria) return "${alias}.status='1'" } public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException { return NO_VALUES } } |
And you can use the above custom condition using as below example:
void checkCustomCriteria() { List list = Table1.createCriteria().list { //setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY) resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP) String scores = AliasBuilder.createAlias0(delegate, "scores", "scores", JoinType.LEFT_OUTER_JOIN, new CustomCriteria()) "projections" { "groupProperty" "id", "id" addProjectionToList(Projections.sqlProjection( "GROUP_CONCAT(${delegate.aliases[scores]}.id) as scores", ["scores"] as String[], [StringType.INSTANCE] as Type[] ), "scores") } } list.each { dataRow-> println("Data row=${dataRow}") } } |
Which will generate below SQL with additional condition on statement ( scores1_.status='1' ) select ... from table1 this_ inner join table2_child scores1_ on this_.id=scores1_.table1_id and ( scores1_.score.status='1' ) where this_.id<>? |
Showing posts with label grails-on-groovy. Show all posts
Showing posts with label grails-on-groovy. Show all posts
Wednesday, October 26, 2022
Grails on Groovy - join tables using createAlias with additional condition along with sql on condition for additional filter of data
Wednesday, August 22, 2018
Grails on Groovy > Way in Grails to Eager Fetch the Whole Record | Load Related Entity With Single Query
I am trying to find if there is any way in Grails to eager fetch complete records instead of a left Join. |
For example, let you have domain named Tabel1 with following structure and another domain named Table3 below: |
package com.pkm class Table1 { Long id String name String roll static mapping = { table("table1") } static belongsTo = [ table3: Table3 ] static constraints = { table3 nullable: true } } package com.pkm class Table3 { Long id String name } |
So when you get/list Table1, what will be the default behavior? It will load only Table1 data, not other associated data like Table3. |
There is a procedure to load selected associated by joining them. See the below example, enabled eager face data when creating criteria: |
package com.pkm import grails.transaction.Transactional import org.hibernate.FetchMode import org.hibernate.sql.JoinType import org.springframework.transaction.TransactionStatus @Transactional class HomeService { TransactionStatus transactionStatus void callMe() { List list = Table1.createCriteria().list { createCriteria("table3", "j3", JoinType.LEFT_OUTER_JOIN) setFetchMode("j3", FetchMode.JOIN) order("id", "desc") setMaxResults(20) } list.each { Table1 table1 -> println("Name=${table1.name}, Table3=${table1.table3?.name}") } } } |
Now we will print the query generated: |
select this_.id as id1_0_1_, this_.name as name2_0_1_, this_.roll as roll3_0_1_, this_.table3_id as table4_0_1_, j3x1_.id as id1_2_0_, j3x1_.name as name2_2_0_ from table1 this_ left outer join table3 j3x1_ on this_.table3_id=j3x1_.id order by this_.id desc limit ? |
You observed that in select query, both Table1 and Table3 exists. And this is how we can implement eager face data when creating criteria builder to get data. |
Thursday, July 12, 2018
Grails on Groovy over Java > Email Address Validation Using Regex
Below is a sample code snippet to validate email address using REGEX |
package com.pkm; import java.util.regex.Pattern; public class EmailValidationRegex { private static final String EMAIL_PATTERN = "^[_A-Za-z0-9-\\+]+([\\.\\+]?[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$"; private static Pattern _pattern = null; public static void main(String[] args) { check("pritomkucse+regex.test@gmail.com"); check("pkm@c.commmmmmmmmmmmmmmmmmmmm"); check("pkm@c.commmmmmmmmmmmmmmmmmmmm."); check("pkm.+invalid@no.valid"); } static void check(String email) { System.out.println(email + " > " + valid(email).toString().toUpperCase()); } static Boolean valid(String email) { return getPattern().matcher(email).matches(); } static Pattern getPattern() { if (_pattern != null) return _pattern; _pattern = Pattern.compile(EMAIL_PATTERN); return _pattern; } } |
Friday, July 6, 2018
Grails on Groovy > GORM dirty checking of instance and properties > grails - tell me if anything is dirty > Checking for Dirty (Updated) Properties on a Grails Domain
GORM provides Grails developers lots of useful hooks, events, methods, and functionality, very important is domain events that inform you when domain objects are being created, updated, and deleted. Within these events, a common use-case is to determine if a particular domain property has changed, and to act accordingly. Below is a code snippet of how you validate your domain before insert or update. |
package com.pkm class Table1 { Long id String name String roll static mapping = { table("table1") } static hasMany = [ scores: Table2 ] void beforeValidate(){ println("BEFORE VALIDATE") } void beforeInsert(){ println("BEFORE INSERT") } void beforeUpdate(){ println("BEFORE UPDATE") } } |
Now, how can you get the actual value of that object? The actual value is modified and you want to get the persisted value. One “not so good” idea is to call refresh() which will load the object from the database again which might be a huge data retrieval in few cases. To solve this problem, GORM has given a simple method which will do the work for you: Below is a example of how you can see which fields are updating in current transaction using below code snippet |
void beforeUpdate(){ println("BEFORE UPDATE") this.dirtyPropertyNames.each { String fieldName -> def oldValue = this.getPersistentValue(fieldName) def newValue = this.getProperty(fieldName) println("\t> VALUE CHANGED FOR $fieldName FROM $oldValue TO $newValue") } } |
The best place to check for dirty properties is usually in the beforeUpdate event. The beforeInsert and afterUpdate events may also seem like good choices at first, but they may not be depending on the use-case. Before inserting, all properties are dirty because they are new, so they haven't really changed they have just been created. After updating, none of the properties are dirty because the new values have already been persisted in your database. These events provide plenty of value if used correctly, but may not always be the best place to check for dirty domain properties. |
One domain in particular that I always perform dirty property checks on is any User domains that my application requires. For instance, if a User object's password has changed, you may want to be alerted in the beforeUpdate event and encrypt the password before it is inserted into your database. |
You also can check if an existing field is dirty or not using this.isDirty("fieldname") |
Be careful not to perform any saves on the domain within these events, as you will get a StackOverflowException. (The event calls .save(), restarting the whole event cycle, where .save() will be called again, and so on. This infinite loop will never end, and the exception will be raised.) |
Otherhand you can check if entire session (hibernate session) is dirty or not. so below is an example how to check if whole hibernate session is dirty or not. |
package com.pkm import grails.transaction.Transactional import org.springframework.transaction.TransactionStatus import org.hibernate.SessionFactory import grails.util.Holders @Transactional class HomeService { TransactionStatus transactionStatus void callMe() { Table1 table1 = Table1.first() table1.roll = System.currentTimeMillis().toString() table1.save() SessionFactory sessionFactory = Holders.applicationContext.getBean(SessionFactory) Boolean isDirty = sessionFactory.currentSession.isDirty() println("IS SESSION DIRTY=${isDirty.toString().capitalize()}") } } |
Saturday, June 23, 2018
When do I need to call this method Runtime.getRuntime().addShutdownHook() > Java.lang.Runtime.addShutdownHook(Thread hook) Method > Java Shutdown hook – Runtime.addShutdownHook() > Grails on Groovy: Add a ShutdownHook > Runtime: addShutdownHook(Thread hook)
The java.lang.Runtime.addShutdownHook(Thread hook) method registers a new virtual-machine shutdown hook.The Java virtual machine shuts down in response to two kinds of events > The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked > The virtual machine is terminated in response to a user interrupt, such as typing ^C, or a system-wide event, such as user logoff or system shutdown |
Below is a example of how shutdown hook can be used: |
package com.pkm; public class RegisterShutDownHook { public static void main(String[] args) { System.out.println("PROGRAM STARTED"); Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { System.out.println("SHUTDOWN HOOK FIRED"); } }); System.out.println("PROGRAM RUNNING"); } } |
Output of the above code snippet would be like below: |
PROGRAM STARTED PROGRAM RUNNING SHUTDOWN HOOK FIRED |
When you are using Grails application, you can do that various process. Either registering shutdown hook or implementing DisposableBean |
Below is the process using shutdown hook |
class BootStrap { def init = { servletContext -> addShutdownHook { println("Running Shutdown Hook"); } } def destroy = { } } |
Or as below, create another class and registering that from resources.groovy like below: |
package com.pkm import org.springframework.context.ApplicationContextAware import org.springframework.context.ApplicationContext class ShutdownHook implements ApplicationContextAware { void setApplicationContext(ApplicationContext applicationContext) { Runtime.runtime.addShutdownHook { println("Application context shutting down...") applicationContext.close() println("Application context shutdown.") } } } // Adding the following block in grails-app/conf/spring/resources.groovy // Place your Spring DSL code here beans = { myShutdownHook(com.pkm.ShutdownHook) } |
And my last known process is using DisposableBean |
package com.pkm import grails.transaction.Transactional import org.springframework.beans.factory.DisposableBean @Transactional class HomeService implements DisposableBean { @Override void destroy() throws Exception { println("APPLICATION DESTROYED") } } |
Sunday, June 17, 2018
Grails on Groovy > Invalidate Session > Error Handling - Session already invalidated
Problem is that in my grails application, when I invalidating the existing http session using session.invalidate() and creating a new session using request.getSession(true) is working fine for some time. |
But this new session is not getting reflected everywhere in grails application. Due to this I do get 'Session already invalidated'. |
I don't want to do request.getSession() everywhere, actually I would not get notified when this required or not. I am just using 'session'. |
Grails holds the reference to a session object and every time you ask it for a session it returns the same reference.. so if you invalidate a session and then ask for the session it will return the same invalidated session, and cause 'session already invalidated' exception.. |
Execute following line Just after you do session.invalidate |
import org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequest session.invalidate() GrailsWebRequest.lookup(request).session = null |
Grails on Groovy > Grails Filter to Redirect HTTP to HTTPS > Redirecting WWW to Root with Grails > Grails Append Something to URL before Redirect > URL Modification On Grails Filters
The problem is need to modify http to https as well as add www to domain name if not exists. To do so have to modify in our Grails Filters.
For Grails applications, a filter can be used to improved security by redirecting traffic from regular HTTP to encrypted HTTPS. The convention is that filters are written in Groovy using filenames ending in Filters, and the files go into the grails-app/conf folder. Redirecting from HTTP to HTTPS provides a better user experience than simply blocking HTTP requests, as redirecting seamlessly forwards users to the web pages they expect to see. |
The example below shows the redirect code |
package com.pkm import grails.util.Environment import javax.servlet.http.HttpServletRequest class SecurityFilters { String getDomainName(HttpServletRequest request) { return request.getRequestURL().substring(0, request.getRequestURL().indexOf("/", 8)) + request.contextPath } String getFullRequestURI(HttpServletRequest request) { String query = request.getQueryString() String request_uri = request.getAttribute("javax.servlet.forward.request_uri") if (request_uri == null) { return request.getRequestURL().toString().substring(0, request.getRequestURL().toString().length() - 1) + (query ? "?$query".toString() : "") } return request.getRequestURL().substring(0,request.getRequestURL().indexOf("/", 8)) + request_uri + (query ? "?$query".toString() : "") } def filters = { filter1(uri: "/**") { before = { Boolean isSecure = request.isSecure(), doRedirect = false String domain = getDomainName(request) String url = getFullRequestURI(request) println("SECURE=${isSecure.toString().capitalize()}" + "\n\t >DOMAIN=${domain}" + "\n\t\t>URL=${url}") /*if (!request.getServerName().toLowerCase().startsWith("www")) { doRedirect = true url = url.substring(0, url.indexOf("//")) + "//www." + url.substring(url.indexOf("//") + 2) }*/ if (!request.isSecure() && !Environment.isDevelopmentMode()) { doRedirect = true url = "https://" + url.substring(url.indexOf("//") + 2) } if (!url.toLowerCase().endsWith("redirected=true-2")) { doRedirect = true url = url + (url.contains("?") ? "&redirected=true-2" : "?redirected=true-2") } if (doRedirect && request.isGet()) { response.setStatus(302) response.setHeader("Location", url) response.flushBuffer() return false } } after = { Map model -> } afterView = { Exception e -> } } } } |
If your server listens for https requests (or any requests on ports other than 80), you can add checks using the same format, replacing http and port 80 with the appropriate values. You can also redirect from any subdomain you want to the root site (or another subdomain), by simply swapping www with your subdomain. |
And output would be like below. First request forwarded to second URL with additional parameters. |
SECURE=False >DOMAIN=http://localhost:3346/CONTEXT_PATH >URL=http://localhost:3346/CONTEXT_PATH/home/index SECURE=False >DOMAIN=http://localhost:3346/CONTEXT_PATH >URL=http://localhost:3346/CONTEXT_PATH/home/index?redirected=true-2 |
Grails on Groovy > Transactions > Transaction Block > Read Only Transactions > With New Transaction > Transactions With Read Only Stage
We all know that Grails services are transactional by default. When you create a service you see that there is a annotation @Transactional exists over class name. Transactional means all transactions will persist on database or no one will persist.
We can set transactions read only mode if we wish in a transactional block if we need. Below is a code snippet: |
package com.pkm import grails.transaction.Transactional import org.springframework.transaction.TransactionStatus @Transactional class HomeService { TransactionStatus transactionStatus void callMe() { Table1 table1 = Table1.last() new Table2(table1: table1, subject: "S3", score: 3D).save() transactionStatus.setRollbackOnly() Table2.withNewTransaction { TransactionStatus tx -> table1 = Table1.last() new Table2(table1: table1, subject: "S4", score: 3D).save() tx.setRollbackOnly() } } } |
In above code block, we inject a bean named transactionStatus which actually maintain if a service definition is read only or not. We can set it to read only mode using transactionStatus.setRollbackOnly(). We can do the same job for when we do anything in withNewTransaction block. You can see there is another transactionStatus occur for that new region. So you can also set it to read only mode. |
Grails on Groovy > Create Criteria > Create Alias > Grails Create Alias > Create Alias With Additional Criteria
We frequently use createAlias to create alias between entity. It actually create connection based on foreign key and primary key between two entities. Below is a example how we create alias between entities: |
Table1.createCriteria().list { createAlias("scores", "scores") } |
Which will produce SQL like below where we can see that foreign key of table1 create a link with table2_child based on primary key id as following: |
select ... from table1 this_ inner join table2_child scores1_ on (this_.id=scores1_.table1_id) |
But if we need more on add to filter when joining them, yeah, we can do that. We can add extra conditions to on part of that SQL. To do so, first need to create a groovy file like below: |
package com.pkm import org.hibernate.Criteria import org.hibernate.HibernateException import org.hibernate.criterion.CriteriaQuery import org.hibernate.criterion.Criterion import org.hibernate.engine.spi.TypedValue class CustomSqlJoin implements Criterion { private Double score = null; CustomSqlJoin(Double score) { this.score = score } //Use Example > createAlias("scores", "scores", JoinType.INNER_JOIN, new CustomSqlJoin(2D)) @Override String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException { String alias = criteriaQuery.getSQLAlias(criteria) return "${alias}.score > ${this.score}" } @Override TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException { return new TypedValue[0] } } |
And you can use the above custom condition using as below example: |
Table1.createCriteria().list { createAlias("scores", "scores", JoinType.INNER_JOIN, new CustomSqlJoin(2D)) "ne" "id", System.currentTimeMillis() } |
Which will generate below SQL |
select ... from table1 this_ inner join table2_child scores1_ on this_.id=scores1_.table1_id and ( scores1_.score > 2.0 ) where this_.id<>? |
Saturday, June 16, 2018
Grails on Groovy > Bind Metamethod of Hibernate Criteria Builder > Create Custom Function / Custom Method Under HibernateCriteriaBuilder > HibernateCriteriaBuilder Meta Method
To bind custom method with hibernate criteria builder you first need to create a groovy file named HibernateCriteriaListener like below: |
package com.pkm import grails.util.Holders import org.codehaus.groovy.grails.commons.GrailsApplication import org.grails.datastore.mapping.core.Datastore import org.grails.datastore.mapping.engine.event.* import org.springframework.context.ApplicationEvent import grails.orm.HibernateCriteriaBuilder class HibernateCriteriaListener extends AbstractPersistenceEventListener { protected HibernateCriteriaListener(Datastore datastore) { super(datastore) HibernateCriteriaBuilder.metaClass.myMethod = { info, value = null -> println("NAME=${info} VALUE=${value}") } } @Override protected void onPersistenceEvent(AbstractPersistenceEvent event) { } @Override boolean supportsEventType(Class<? extends ApplicationEvent> aClass) { return false } static void initialize(GrailsApplication application) { application.mainContext.eventTriggeringInterceptor.datastores.each { k, datastore -> Holders.applicationContext.addApplicationListener(new HibernateCriteriaListener(datastore)) } } } |
Now we need to register the above functionality from BootStrap, so you need to do following: |
import com.pkm.HibernateCriteriaListener import org.codehaus.groovy.grails.commons.GrailsApplication import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes import org.hibernate.dialect.function.SQLFunctionTemplate import org.springframework.context.ApplicationContext class BootStrap { def init = { servletContext -> ApplicationContext applicationContext = servletContext.getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT) GrailsApplication application = (GrailsApplication) applicationContext.getBean("grailsApplication") /* REGISTER HIBERNATE EVENT LISTENER */ HibernateCriteriaListener.initialize(application) } def destroy = { } } |
And finally you can use custom criteria method using below sample: |
Table1.createCriteria().list { delegate.myMethod("name", "value") } |
Subscribe to:
Posts (Atom)