It’s hard to increment null

After watching Jason Rudolph build a Grails application around an existing, legacy database, I decided to see if I could do the same. My Google Maps application (see my earlier posts on the subject) gave me a reason to finally put my courses taught data into a database. I still need a way to insert new data into that database, in a more user-friendly way than typing raw SQL at the MySQL command line.

Of course, that’s an ideal application for Grails. The Grails scaffolding builds controllers and views that can display domain objects that map to database tables, update existing objects, and even insert new ones. At my stage of learning Grails, it’s very useful for me to let the automatic generators build the basic application and then gradually replace the scaffolding with code I like.

This is also a nice app to experiment with, because at the moment it’s got a whopping three tables in it. There are three obvious domain objects, too: Course, Client, and Location. I’ve also got two one-to-many relationships between them, in that a client has many courses, and a location also has many courses. Nice and simple, but at least more than just a Grails version of Hello, World.

In Grails, it’s easiest to develop if you don’t already have a database. In a way, it’s ideal for domain-driven design, because you start with your domain objects and their relationships, and everything flows from there.

If I was starting from scratch, my domain classes (in Groovy) would look like:


class Client {
    int id
    String name

    static hasMany = [courses:Course]

    String toString() {
        return name
    }
}

for the Client, where the toString() override is so the relationship drop-down lists will be populated with just the name. Also, the hasMany closure establishes the relationship between Client and Course, at least on this end.

The Location class is


class Location {
    int id
    String city
    String state
    double latitude
    double longtitude

    static hasMany = [courses:Course]

    static constraints = {
        city(blank:false)
        state(blank:false)
        latitude()
        longitude()
    }

    String toString() {
        return "${city}, ${state}"
    }
}

The latitude and longitude fields are for the Google Maps application. The hasMany closure establishes the relationship between Location and Course. The constraints closure puts the various fields in the order listed, and ensures that neither city nor state can ever be empty. The resulting validation and highlighted error messages are part of the coolness Grails brings to the table.

Finally, the Course class is:


class Course {
    int id
    Date startDate
    Date endDate
    String title

    Location location
    Client client

    static belongsTo = [Client, Location]

    String toString() {
        return title
    }

    static constraints = {
        title(blank:false)
        startDate()
        endDate()
    }
}

The Course uses the belongsTo closure to establish the relationships in the other direction. The constraints closure is still mostly just for ordering; I imagine I’ll expand it later.

Now, if I didn’t have an existing database, I’d start with this, generate all the scaffolding, and let Grails create the database schema. The thing is, though, I already have the database schema, and some data to go in it.

As Jason showed, I could just let the Hibernate Tools reverse engineer mapping files from my schema. Then I could edit the mapping files to make the existing schema fit my domain classes.

Still, I thought I’d just edit the database to fit the Grails conventions (cue ominous music in the background). I’m doing this application as much to learn Grails as to solve my problem. Even better, I already have a Groovy script that can repopulate the tables if necessary using my existing DAO layer, currently written in Java with Spring and JPA.

The first change I made from my earlier schema was to make the table names singular instead of plural. The rest was fine (or so I thought). Each table had a primary key called id of type int. The course table has two foreign keys, each of which follows the naming convention (location_id and client_id). All of the column names map to the field names in the classes above, with camel case replaced by snake case (i.e., the startDate field maps to the start_date column).

Everything looked good, so I called the various Grails generators (grails create-app, grails create-domain-class, grails create-controller, and finally grails generate-scaffold) to see what happened.

As an aside, I also edited my DataSource.groovy file to point to my MySQL installation and to get rid of the dangerous “create-drop” capability. I didn’t want to overwrite the data by accident.

Unfortunately, I missed a detail. Grails doesn’t just add in a primary key field called id. It also expects a column called “version” in the database, of some integer type. This column is used for optimistic locking, so that if two people are editing a column at the same time, the one to commit first gets their changes written. The person who commits afterwards gets an error telling them that their data is stale, so they can’t commit until they refresh their data to the current values.

I don’t have version columns in my tables. Or, rather, I didn’t. I figured rather than drop everything, regenerate the tables and repopulate them from scratch, I could just execute “alter table” statements to add the new column to each of the three tables. I went ahead and did that.

The application then came up just as it should. I could see all the data, insert new rows, and delete the ones I inserted. Kewl. I spent some time editing the displays to order the data, make the views more visually appealing, and add functionality to search the courses by title and/or year (thanks to Jason’s great Getting Started With Grails book for all that).

What I couldn’t do, no matter what I tried, was to edit an existing object and have it successfully commit the changes. The web pages said that the changes were successful, so the save() method was supposedly returning true. The console didn’t show any errors, either. But nothing was changing in the database.

I really had to dig to figure that one out, but the Red Sox were losing and the Yankees were winning, so I kind of needed something to distract me anyway.

As it turned out the “grails shell” was the key. The Grails shell is a command-line script that allows you to write Groovy code that works with the existing domain classes. I loaded a course, modified its title, and tried to save it.

The resulting several hundred thousands of lines of the exception stack trace (Grails really can generate reams of lines of exceptions) somewhere had the word “version” in it.

I opened up a MySQL shell and looked at my data. Lo and behold, the version columns I added were there, and the data type was int, but of course all of the entries were null. Not zero, but null.

The optimistic lock tries to increment the value in that column. As it turns out, it’s hard to increment null.

The answer was to put zeros in all the version values. Everything worked just fine after that.

There’s a lot more I can and will do with this, but I have to admit, it was an excellent learning experience. It’s a bit daunting to know, however, that not having a version column meant that I almost had to switch to mapping files.

About Ken Kousen
I teach software development training courses. I specialize in all areas of Java and XML, from EJB3 to web services to open source projects like Spring, Hibernate, Groovy, and Grails. Find me on Google+ I am the author of "Making Java Groovy", a Java / Groovy integration book published by Manning in the Fall of 2013, and "Gradle Recipes for Android", published by O'Reilly in 2015.

5 Responses to It’s hard to increment null

  1. Just a minor correction: ‘hasMany’ and ‘belongsTo’ are not closures but static java.util.List properties.

  2. Ken Kousen says:

    Interesting. I hadn’t thought of them that way. I understood that we assigned closures to them, but I hadn’t realized what they actually were.

    Thanks for the info.

  3. voituk says:

    It not so easy to call null.next() too 🙂
    Nice success story post.

  4. Ken Kousen says:

    Thanks. I really hope that by documenting my mistake, I’ll help someone else avoid it. I guess I just figured that doing an “alter table” statement and making the new column of type int, the values would be initialized to zero. No such luck.

    Of course, I got a (mildly) funny story out of it, so that’s good too.

  5. thanks for the GREAT post! Very useful…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: