Lazylob Plugin

0 vote
Dependency:
compile ":lazylob:0.1"

 Documentation  Source  Issues

Summary

Adds support for lazy-loaded Blobs and Clobs

Description

This plugin adds support for lazy-loaded Blobs and Clobs. Grails supports large objects in domain classes but they are always eagerly loaded when you retrieve domain class instances. One approach is to put the Blob/Clob in a separate domain class and configure a lazy-loaded one-to-one mapping, but this tends to be an artificial workaround that complicates the domain model. Hibernate has no direct support for making them lazy like collections and many-to-one references, so this plugin fills that gap.

Install the plugin by adding a dependency in the plugins section of BuildConfig.groovy, e.g.

plugins {
   compile ':lazylob:0.1'
}

To use this feature, change the data type of your java.sql.Blob and java.sql.Clob fields to grails.plugin.lazylob.LazyBlob and grails.plugin.lazylob.LazyClob respectively. The plugin provides a Hibernate custom UserType for each data type to manage persistence, so add that configuration to the mapping block, e.g.

package com.yourcompany.yourapp

import grails.plugin.lazylob.LazyBlob import grails.plugin.lazylob.LazyBlobType

class YourClass { LazyBlob theBlob // other properties

static mapping = { theBlob type: LazyBlobType, params: [propertyName: 'theBlob'] } }

The user type needs to know the property name of the field so it can determine the database column name when it loads the data, so that must be added to the params Map. This means that it's not an option to add the type to the grails.gorm.default.mapping since this that doesn't support parameterized types (and the parameters would likely be different for each domain class).

Lazy clobs are similar:

package com.yourcompany.yourapp

import grails.plugin.lazylob.LazyClob import grails.plugin.lazylob.LazyClobType

class YourOtherClass { LazyClob theClob // other properties

static mapping = { theClob type: LazyClobType, params: [propertyName: 'theClob'] } }

Creating and persisting domain classes with lazy objects is similar to the approach when you use regular Blobs and Clobs, except that the lazy types need a reference to their owning domain class instance so the domain class cannot be completely created in one step with the Map constructor:

def thing = new YourClass(foo: 42, bar: true)
byte[] bytes = …
thing.theBlob = new LazyBlob(bytes, thing)
thing.save()

Loading an instance is the same as usual. The Blob or Clob data will only be loaded if you call one of the interface methods:

def id = …
def thing = YourClass.get(id)
println thing.theBlob.isInitialized() // prints false, doesn't trigger loading
println thing.foo // doesn't trigger blob loading
println thing.theBlob.length() // triggers loading
println thing.theBlob.isInitialized() // prints true

You can also create instances with exising Blobs or Clobs:

def thing = new YourClass(foo: 42, bar: true)
Blob blob = …
thing.theBlob = new LazyBlob(blob, thing)
thing.save()

and when you load the instance it will use a @LazyBlob@.

LazyClobs are similar:

def thing = new YourOtherClass(foo: 42, bar: true)
String string = …
thing.theClob = new LazyClob(string, thing)
thing.save()

and

def thing = new YourOtherClass(foo: 42, bar: true)
Clob clob = …
thing.theClob = new LazyClob(clob, thing)
thing.save()