Search code examples
grailsgroovygrails-orm

GORM: mapping large text fields database agnostically


I have a Grails application that will run against either a SQL Server or Oracle backend. I am using GORM as an ORM.

I want to map a large text field in a way that supports both database types. In my Grails domain class I have something like:

class Note {
    String content

    static constraints = {
        content nullable: false, blank: false
    }
}

I then declare database tables that look like this:

-- oracle
CREATE TABLE NOTE 
(
    id NUMBER(19, 0) NOT NULL,
    version NUMBER(19, 0) NOT NULL,
    content CLOB NOT NULL
);

-- SQL Server
CREATE TABLE NOTE 
(
    id NUMERIC(19, 0) NOT NULL,
    version NUMERIC(19, 0) NOT NULL,
    content NVARCHAR(MAX) NOT NULL
);

GORM is running in validate mode on startup, and I can't find a combination of Oracle and SQL Server data types and GORM mappings that allow the storage or large text fields without GORM failing to start correctly.

I have tried:

  • setting the type to text in mappings, but this doesn't seem to work. Oracle complains about expecting the content field to be of type long, and SQL Server wants a type of text in these circumstances.

  • setting the type to clob, which passes schema validation but then doesn't allow me to set the field as a string value - GORM expects data of type CLOB.

How should I configure my database definitions and GORM to make this work?


Solution

  • As hackish as it is, a solution eventually emerged: by querying the Grails configuration at startup time, you can select an appropriate data type.

    class Note {
    
        String content
    
        static constraints = {
            content nullable: false, blank: false
        }
    
        static mappings = {
            content sqlType: DbSupport.bigStringType
        }
    }
    
    class DbSupport {
    
        static def getBigStringType() {
    
            // examine which hibernate dialect is selected, and pick
            // an appropriate type mapping for that database type:
            def dialect = ApplicationHolder.application.config.dataSource.dialect
            switch (dialect) {
    
                case "org.hibernate.dialect.SQLServerDialect":
                    return "nvarchar"
                    break
    
                case "org.hibernate.dialect.Oracle10gDialect":
                    return "clob"
                    break
            }
    
        }
    }