Autobase

  • Tags : persistence, database, migration
  • Latest : 1.0.0.0
  • Last Updated: 06 February 2012
  • Grails version : 1.2.1 > *
  • Authors : null
9 votes
Dependency :
compile ":autobase:1.0.0.0"

Documentation Source

Summary

Installation

grails install-plugin autobase

Description

The Autobase plug-in was replaced by the Database Migration plug-in, that also uses Liquibase. If you are starting a new project, you should probably prefer Database Migration. The plugin is still there mainly to support legacy projects.

This plugin marries the established Liquibase core with Grails development processes in order to allow migrating your database schema and store its evolutions under source control.

The approach to this plugin is to leave the database update mode ("hbm2ddl.auto" value) as "" (empty string), and to manage alterations to the database schema through changesets into Migration class. The changesets are made up of Liquibase's many "refactorings": http://www.liquibase.org/manual/home

Introduction

Grails does a lot to help you create your data model without having to worry about the database schema. But when your data model changes, your existing database schema has to evolve too. Leaving this role to the Hibernate's update can be dangerous for your data as it handles only very basic changes (adding a column...). Renaming an existing table or column won't work for instance.

Liquibase allows you to describe the creation and update of your database schema. The Autobase plug-in provides integration of Liquibase in Grails:

  • Changesets are written in Groovy.
  • Migrations can be described in a plug-in.
  • Migration order can be controlled easily.

Example

Create a grails project and install the autobase plug-in:

grails create-app Example
cd Example
grails install-plugin autobase

Now create a domain class and add a few properties:

grails create-domain-class com.mycompany.Book

class Book {
    String title

int nbPages

static constraints = { title(maxSize: 200) } }

As you set update to "", Hibernate won't create the database for you anymore. This is the slight drawback: you have to create it by hand. But you gain more control on how the database evolves, which will avoid catastrophic migrations.

Run the command to create the migration:

grails create-migration com.mycompany.Book

It will create a new class named BookMigration under grails-app/migrations/. Modify it so that it looks like this:

class BookMigration {
    static migration = {
        changeSet(id:'BOOK_1', author:'Bob') { 
            createTable( tableName: "book") {
                column(name:"id",type:"bigint",autoIncrement:true){
                    constraints( primaryKey: "true", nullable: "false" )
                }
                column(name:"version", type: "bigint")
                column(name:"title", type: "varchar(200)")
                column(name:"nb_pages", type: "int")
            }
        }
    }
}

The properties id and version are automatically generated by Grails. You can have an help to know what the tables should look like by running:

grails schema-export

It will generate a DDL file of the schema that Hibernate would have generated.

Start your application and use a tool to look at your database schema. You will see that the book table was created.

Now, let's say that you update your domain class. You must also update your database schema:

class Book {

String title

int pages // was nbPages

static constraints = { title(maxSize: 200) } }

You should create a new changeset in your migration. Your migration class to something looking like this:

class BookMigration {
    static migration = {
        changeSet(id:'BOOK_1', author:'Bob') { 
            createTable( tableName: "book") {
                column(name:"id",type:"bigint",autoIncrement:true){
                    constraints( primaryKey: "true", nullable: "false" )
                }
                column(name:"version", type: "bigint")
                column(name:"title",type:"varchar(200)")
            }
        }

changeSet(id:'BOOK_2', author:'Bob') { renameColumn(tableName:"book", oldColumnName:"nb_pages", newColumnName:"pages") } } }

After reloading, you will see that your schema was modified to rename the column nb_pages to pages.

Available migrations

Liquibase proposes different refactorings like renaming or dropping columns, adding and removing constraints, and more. You can find a list here: http://www.liquibase.org/manual/home

Ordering migrations

You will probably need to run the migrations in a certain order, if some of your changesets depend on other migration classes (foreign key constraints for instance). You can do it by adding a static runAfter property containing a list of all the migrations that should be executed before:

class BookMigration {

static runAfter = [ AuthorMigration ]

static migration = { … } }

Changelog

1.0.0.0

  • Migration to Liquibase 2.0.3.
  • Some cleaning in the code.

Roadmap

  • v1.0
    • Move dependencies to BuildConfig.groovy.
    • Allow to activate Autobase depending on the environment.