Showing posts with label gorm. Show all posts
Showing posts with label gorm. Show all posts

Monday, November 7, 2016

Hooking into or extends the GormInstanceApi methods of the GORM API for Grails

Main class defination


package com.autobill.enhancer

import org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass
import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore
import org.codehaus.groovy.grails.orm.hibernate.HibernateGormInstanceApi
/**
 * Created by pritom on 17/10/2016.
 */
class MyCustomInstanceApi<D> extends HibernateGormInstanceApi<D> {
    private HibernateGormInstanceApi gormInstanceApi

    MyCustomInstanceApi(HibernateGormInstanceApi gormInstanceApi) {
        super(gormInstanceApi.persistentClass, gormInstanceApi.datastore as HibernateDatastore, gormInstanceApi.classLoader)
        this.gormInstanceApi = gormInstanceApi
    }

    @Override
    D save(D instance) {
        println("Saving-${instance}")
        super.save(instance)
    }

    static void init(servletContext) {
        servletContext.grailsApplication.domainClasses.each { DefaultGrailsDomainClass domainClass ->
            def gormInstanceApi = domainClass.clazz.currentGormInstanceApi()
            domainClass.clazz.setInstanceGormInstanceApi(new MyCustomInstanceApi(gormInstanceApi))
        }
    }
}

And invoke MyCustomInstanceApi.init(servletContext) from Bootstrap.groovy

Monday, May 5, 2014

Logging Hibernate SQL in Grails With Parameters

Add the following line to DataSource.groovy marked yellow


dataSource {
    pooled = true
    url = jdbc:mysql://localhost/database_name?useUnicode=yes&characterEncoding=UTF-8
    driverClassName = com.mysql.jdbc.Driver
    username = database_user_name
    password = database_password
    dialect = org.hibernate.dialect.MySQL5InnoDBDialect
    dbCreate = "update"
    logSql = true
    properties {
        maxActive = 1000
        maxIdle = 100
        minIdle = 50
        initialSize = 1
        minEvictableIdleTimeMillis = 60000
        timeBetweenEvictionRunsMillis = 60000
        numTestsPerEvictionRun = 3
        maxWait = 10000
        testOnBorrow = true
        testWhileIdle = true
        testOnReturn = true
        validationQuery = "SELECT 1"
    }
}

Add the following two code block to last of the file


log4j = {
    debug 'org.hibernate.SQL'
    trace 'org.hibernate.type.descriptor.sql.BasicBinder'
}

hibernate {
    cache.use_second_level_cache = true
    cache.use_query_cache = true
    cache.region.factory_class = 'net.sf.ehcache.hibernate.EhCacheRegionFactory'
    cache.provider_class = 'net.sf.ehcache.hibernate.EhCacheProvider'
    format_sql = false
    use_sql_comments = true
}

Example output of trace/debug


Hibernate: /* insert com.pkm.LogTest */ insert into log_test (created, name, display_name, a_long_value) values (?, ?, ?, ?)
2014-05-05 09:42:44,803 [http-bio-8011-exec-10] TRACE sql.BasicBinder  - binding parameter [1] as [TIMESTAMP] - Mon May 05 09:42:44 ALMT 2014
2014-05-05 09:42:44,803 [http-bio-8011-exec-10] TRACE sql.BasicBinder  - binding parameter [2] as [VARCHAR] - Pritom Kumar Mondal
2014-05-05 09:42:44,803 [http-bio-8011-exec-10] TRACE sql.BasicBinder  - binding parameter [3] as [VARCHAR] - pritom
2014-05-05 09:42:44,803 [http-bio-8011-exec-10] TRACE sql.BasicBinder  - binding parameter [4] as [BIGINT] - 3

Tuesday, February 18, 2014

Hooking into GORM custom event listener from plugin in Grails

In our custom listener, the method ‘onPersistenceEvent’ is called on all GORM events that we filter to what we interested – PreInsert, PreUpdate
Create a groovy file under src/groovy suppose named 'FieldValidationListener.groovy' with the following contents. And create required method in your domain class, suppose one method can be named: 'doValidationPreInsert' or 'doValidationPreUpdate'.

package com.groovy.fieldSetting

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

/**
 * Created by pritom on 17/02/14.
 */
class FieldValidationListener extends AbstractPersistenceEventListener {
    public FieldValidationListener(Datastore datastore) {
        super(datastore)
    }

    @Override
    protected void onPersistenceEvent(AbstractPersistenceEvent event) {
        String operation;
        switch (event.eventType) {
            case EventType.PreInsert:
                operation = "PreInsert"
                break;
            case EventType.PreUpdate:
                operation = "PreUpdate"
                break;
        }
        if(operation) {
            String methodName = "doValidation${operation}"
            println "Searching for method: ${methodName}"
            if (event.entityObject.respondsTo(methodName)) {
                try {
                    event.entityObject."${methodName}"()
                } catch (Exception exp) {
                    event.cancel();
                    throw exp;
                }
            }
        }
    }

    @Override
    boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
        if ([PreInsertEvent, PreUpdateEvent].any { def supportedType ->
            if (supportedType.isAssignableFrom(eventType)) {
                return true
            } else {
                return false
            }
        }) {
            return true
        } else {
            return false
        }
    }

    public static void initialize(GrailsApplication application) {
        application.mainContext.eventTriggeringInterceptor.datastores.each { k, datastore ->
            Holders.applicationContext.addApplicationListener(new FieldValidationListener(datastore))
        }
    }
}

And initialize start listening, insert the following code block into 'BootStrap.groovy' [in 'init' method]:

FieldValidationListener.initialize(grailsApplication)

Saturday, February 15, 2014

Accessing i18n Messages from exception (validation errors) in Grails in a Service

To access your message, inject the MessageSource into your service:
def messageSource  

And to get the error messages from exception based on your i18n properties file, use the following code block in your service:
 
def messageSource;

def printAllMessage(Exception ex) {
    ex.errors.allErrors.eachWithIndex { ObjectError objectError, Integer index ->
        println "Error #${index}: " + messageSource.getMessage(objectError, Locale.default);
    }
}


Will output something like this based on you i18n messages.properties file:

Error #0: Property [accountId] cannot be null
Error #1: Property [displayName] cannot be null
Error #2: Property [emailAddress] with value [pritom@bitmascot.com] must be unique

If your i18n file contains something like:

default.null.message=Property [{0}] cannot be null
default.not.unique.message=Property [{0}] with value [{2}] must be unique

Tuesday, October 29, 2013

Grails/GORM createCriteria.list to get specific/selected columns only | Alias To Entity Map ALIAS_TO_ENTITY_MAP | Grails Projections | Projections Data

Grails/GORM createCriteria.list to get specific/selected columns only | Alias To Entity Map ALIAS_TO_ENTITY_MAP | Grails Projections | Projections Data.

Below is a example of get some specific field instead of all fields for domain.

And you can left join another domain that is belongsTo or hasMany of parent domain.


You have to import below reference:

import org.hibernate.criterion.CriteriaSpecification

List list = DomainName.createCriteria().list {
    resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)
    "in"("id", [1L, 2L])
    createAlias('x', 'x_alias', CriteriaSpecification.LEFT_JOIN)
    projections {
        property("id", "id")
        property("x_alias.field", "field_reference");
    }
}

Output would be like below:

[
    [id:1, field_reference:value1],
    [id:2, field_reference:value2]
] 

Monday, October 28, 2013

Grails get post/put raw request body

There may be situation where the data in body for the request is need to be read. To read the raw data:
request.getReader().text

However, this will give the following error:
getInputStream() has already been called for this request

This is because the default request parser needs to be turned off before reading the body text. Here is one way how to do it in the grails-app/conf/UrlMapping:
class UrlMappings {
    static mappings = {
        "/api/review/$id?"(controller: 'review', parseRequest: false){
            action = [ PUT: "update", POST: "save", GET: "show"]
        }
...
}
By specifying ‘parseRequests: false’ in highlighted line, it will turn off the Grails automatic parsing and make it possible to read the body data (i.e. request.getReader().text)

You can read request body in your filters before method and parse if need as you wish.
 

Friday, October 25, 2013

Grails GORM constrained properties: check if a domain attributes properties mapping

Consider a grails domain class like below:



package com.pritom.domains.customer

class Customer {
    Integer id;
    String customerId
    String email;
    String password
    Date dateCreated = new Date()
    Date lastUpdated = new Date()

    static mapping = {

    }

    static constraints = {
        customerId unique: true
        email unique: true
        creditCard(nullable: true);
    }
}

Now get domain class constrained properties:



def domainClass = new DefaultGrailsDomainClass(com.pritom.domains.Customer)
def constrainedProperties = domainClass.constrainedProperties;

Now check if specific field has some specific property



String key = "customerId";

if (constrainedProperties.containsKey(key)) {
    ConstrainedProperty v = (ConstrainedProperty) constrainedProperties.get(key);
    if(v.isNullable()) println 'Nullable';
    if(v.isBlank()) println 'Blank';
    if(v.isCreditCard()) println 'Credit Card';
    if(v.isDisplay()) println 'Display';
    if(v.isEditable()) println 'Editable';
    if(v.isEmail()) println 'Email';
}


And you can check more properties as you wish.

http://pritomkumar.blogspot.com/2013/09/javagrails-class-constrainedproperty.html

Wednesday, October 23, 2013

Duplicated records/data persistence/flush session error with Grails in synchronized method

Consider some of cases: 

  1. When domain fails to save data because of duplicate record.
  2. When an unsaved domain belongsTo a domain, then showing: 'save the transient instance before flushing'.
Then  - Domain.save(flush:true) - didn't work because of threading.
Here is example of my thread creation:
Thread.start {
    Domain.withTransaction {
         // Doing stuff and calling synchronization method to write data to DB
    }
}
Fix was found here: Grails, GPars and data persistence
I replaced "Domain.withTransaction" with "Domain.withNewSession":
Thread.start {
    Domain.withNewSession {
         // Doing stuff and calling synchronization method to write data to DB
    }
}
and save(flush:true) start writing into mySQL. Since data is written to mySQL, findBy... start returning proper results and therefore I application doesn't try to create duplicated record anymore. Issue solved!

Monday, October 21, 2013

Grails GORM creating foreign key on runtime

GORM mappings let you configure pretty much anything you need in your Grails applications, but occasionally there are more obscure tweaks that aren’t directly supported, and in this case a custom Configuration class is often the solution.

By default Grails uses an instance of GrailsAnnotationConfiguration and the standard approach is to subclass that to retain its functionality and override the secondPassCompile() method.

Create this class (with an appropriate name and package for your application) in src/java or src/groovy:


package com.pritom

import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration
import org.hibernate.mapping.Column
import org.hibernate.mapping.ForeignKey
import org.hibernate.mapping.PersistentClass

/**
 * Created with IntelliJ IDEA.
 * User: pritom
 * Date: 21/10/13
 * Time: 10:41 AM
 * To change this template use File | Settings | File Templates.
 */
class GormConfiguration extends GrailsAnnotationConfiguration {
    boolean renamedForeignKeys = false

    @Override
    protected void secondPassCompile() {
        super.secondPassCompile()

        if (renamedForeignKeys) {
            return
        }

        renameForeignKeys()
        renamedForeignKeys = true
    }

    void renameForeignKeys() {
        classes.values().each { PersistentClass persistentClass ->
            /**
             * There must be a domain name 'SportUser' which has a field 'user_id'.
             */
            if(persistentClass.entityName.equalsIgnoreCase("com.pritom.SportUser")) {
                persistentClass.table.columns.each {
                    /**
                     * user_id: Column name to behave as a foreign key
                     * There must be a domain name 'User' to linked with it.
                     */
                    if(it.value.name.equalsIgnoreCase("user_id")) {
                        Column column = (Column) it.value;
                        /**
                         * ACL_USER: Foreign key constraints name
                         * com.pritom.User: Domain to make the foreign object
                         */
                        persistentClass.table.createForeignKey("ACL_USER", [column], "com.pritom.User")
                    }
                }
            }
        }
    }

    String createHumanReadableName(ForeignKey key) {
        "${key.columns.first().name}__${key.referencedTable.name}_fkey"
    }
}


What is left is to activate the code which is a one liner, we just have to add a configClass parameter to the datasource configuration:

    dataSource {
        configClass = com.pritom.GormConfiguration
        driverClassName = "com.mysql.jdbc.Driver"
        dbCreate = "create"
        url = "jdbc:mysql://localhost/grails_db"
        username = "grails"
        password = "grails"
    }  

Grails: renaming foreign keys constraints

In Grails if we create a domain class with association we will get a foreign key for the association. Let’s see how the foreign key gets named using an example using a many-to-one association.
Here is a simple domain class with an association to itself.

package gorm

class Category {
    Category child
}
The create table for this class will look like this:
CREATE TABLE category (
    id bigint NOT NULL,
    version bigint NOT NULL,
    child_id bigint,
    CONSTRAINT category_pkey PRIMARY KEY (id),
    CONSTRAINT fk302bcfeabee40a7 FOREIGN KEY (child_id)
        REFERENCES category (id)
)
We can see that the primary key gets a human readable name category_pkey but the name of the foreign key is fk302bcfeabee40a7. Not too readable. It would be nice if we could give the foreign key a human readable name too. What about <COLUMN>_<TARGET_TABLE>_fkey to make it similar to the name of the primary key?
It looks like Grails does not offer any GORM DSL sugar to customize the name of the foreign key. But naming it manually on each domain class may be a bit cumbersome anyway. It would be nice if we could make it use the <COLUMN>__<TARGET_TABLE>_fkey format automatically.

Here is a version in groovy implementing the format given above:

package com.pritom

import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration
import org.hibernate.mapping.PersistentClass
import org.hibernate.mapping.ForeignKey

/**
 * Created with IntelliJ IDEA.
 * User: pritom
 * Date: 21/10/13
 * Time: 10:41 AM
 * To change this template use File | Settings | File Templates.
 */
class GormConfiguration extends GrailsAnnotationConfiguration {
    boolean renamedForeignKeys = false

    @Override
    protected void secondPassCompile() {
        super.secondPassCompile()

        if (renamedForeignKeys) {
            return
        }

        renameForeignKeys()
        renamedForeignKeys = true
    }

    void renameForeignKeys() {
        classes.values().each { PersistentClass persistentClass ->
            persistentClass.table.foreignKeyIterator.each { ForeignKey key ->
                key.name = createHumanReadableName(key)
            }
        }
    }

    String createHumanReadableName(ForeignKey key) {
        "${key.columns.first().name}__${key.referencedTable.name}_fkey"
    }
}
It is not perfect. We do not check the length of the generated name and there are are probably other details I do not know anything about yet we have to take care of. But it it a start. :-)
The create table now look like this:
CREATE TABLE category (
    id bigint NOT NULL,
    version bigint NOT NULL,
    child_id bigint,
    CONSTRAINT category_pkey PRIMARY KEY (id),
    CONSTRAINT child_id__category_fkey FOREIGN KEY (child_id)
        REFERENCES category (id)
)
With a nicely named foreign key. :-)
What is left is to activate the code which is a one liner, we just have to add a configClass parameter to the datasource configuration:
    dataSource {
        configClass = com.pritom.GormConfiguration
        driverClassName = "com.mysql.jdbc.Driver"
        dbCreate = "create"
        url = "jdbc:mysql://localhost/grails_db"
        username = "grails"
        password = "grails"
    }  

Tuesday, October 1, 2013

Grails domain class: unique constraint for multiple columns

Suppose a simple Grails domain class:


class Account {
    String countryId;

    String userName; 
 
    String areaId;
 
    String password;

    static constraints = {
        ...???...
    }
}


It is required that user names are unique for a particular countryId and areaId, thus there must be a unique contraint on three columns. And this is the constraints:

userName(unique: ['countryId', 'areaId'])
 
You can include as many other properties in the array that make up the 
other properties that must be considered in the "unique" constraint on 
the username. 

Monday, May 20, 2013

Groovy Grails Domain GORM and enum types


Create an enum class in src/groovy or src/java.

/**
 * User: pritom
 */
public enum UserStatus {
    active('active'),
    on_hold('on_hold')

    String name

    UserStatus(String name) {
        this.name = name
    }

    public String getName() {
        name
    }

    public String toString() {
        return this.getName()
    }
}

Specify a property in your domain class with the enum type.

class User {
 String userName,
 UserStatus type = UserStatus.active
}