Wednesday, May 16, 2012

Worklog part2: Domain objects and relations in GORM

Last time, we created the domain-class User. Meanwhile I found this name a bit ambiguous, so I renamed it to Employee. In addition to Employee, I need some other domain-objects to support my application. I need a Company, Department, Customer, Project, ProjectExpense, ProjectWorkUnit. And of course these are related in some way or another, leveraging the powers of GORM.
First off, let´s create the domain-classes using the grails interactive mode
// start interactive mode by typing "grails"

# create-domain-class worklog.Employee
# create-domain-class worklog.Company
# create-domain-class worklog.Department
# create-domain-class worklog.Customer
# create-domain-class worklog.Project
# create-domain-class worklog.ProjectExpense
# create-domain-class worklog.ProjectWorkUnit
# create-domain-class worklog.ProjectRole
Now, a company can have several departments. To tell GORM about this relation, I simply use the "hasMany" property in Company, along with some other sane constraints:
package worklog

class Company {

    String domain
    String name
    Date dateCreated

    static hasMany = [ department:Department]

    /**
     * hibernate plugin event-method
     * @return
     */
    def beforeInsert(){
        dateCreated = new Date()
    }

    static constraints = {
        domain(unique: true)
        name(nullable: false)
    }

    String toString(){
        domain
    }
}

By default all properties are non-nullable in GORM, but I like to specify non-nullable constraints I think are important for my domain-class. The "hasMany" keyword tells GORM that Company can have 0 or more departments. The domain-property is unique for each Company, so I added the unique-constraint. Before inserting a new Company into the database, the beforeInsert() method is run by GORM, so I grab the opportunity to put a createdDate on the object.
It´s possible(and necessary) to have several relations declared in the hasMany property. For example, a project can have related both roles, expenses and work-units:
class Project{
  ...
  static hasMany = [projectRoles: ProjectRole, projectWorkUnits:ProjectWorkUnit, projectExpenses:ProjectExpense]
  ...
}
Also, an employee has to know to wich department he/she belongs to, expressed by the belongsTo keyword.
...
class Employee{
  static belongsTo = [department:Department]
}
...
Now, my total domain model is mapped and since I use intellij, a nice drawing of my relations are illustrated like this:


With a nice domain-model in place, I need some test-data to test my app locally. In my Bootstrap.groovy-file there is an init-method. This will be run every time the application starts, so we can add some test-data here. Grails has built-in methods to check for what environment we are in so we don´t create test-data in our production environment.
class BootStrap {

    def init = { servletContext ->
        switch (Environment.current) {
            case Environment.DEVELOPMENT:
                Company webstep = new Company(name: "webster", domain: "webstep.no").save()
                Department oslo = new Department(company: webstep, name: "Konnsulting", city: "Oshlo").save()
                Employee nils = new Employee(department: oslo, email: "nilsmagnus@gmail.com", securityRole: SecurityRole.NORMAL).save()
                Customer icu = new Customer(name: "icu").save()
                Project icuRefactoring = new Project(department: oslo, customer: icu, name: "refactoring legacy code").save()
                ProjectRole developer = new ProjectRole(employee: nils, project: icuRefactoring, hourRate: 1200.0, description: "Develop some cool shait").save()
                ProjectExpense calculatorPurchase = new ProjectExpense(description: "new calculator", project: icuRefactoring, projectRole: developer, amount: 1300.0 ).save()

                break
        }
    }
}
This fills in some data for testing purposes, now we just need to see the data in our app. To get started with ui, I think it´s nice to generate html and controllers with grails using the built in "generate-all" command. For each domain-class I enter the command
# generate-all worklog.Employee
....
# run-app
And its time for inspection :)
To recap: GORM takes care of database-mapping and intellij shows you the relations in your app. Easy as that. Next time: some testing. Later on I will be doing the gorm critierias to create nice reports.

No comments:

Post a Comment