Search code examples
grailsgrails-orm

Updating a primary key value on grails gorm


I'm wondering if I can change a value of a primary key member of a composite primary key in a Grails Domain class? For example having this domain:

class StudentHistory implements Serializable {
    String studentNumber
    String schoolYear
    Integer yearLevel
    String section
    Float average
    String status

    static mapping = {
        ...
        id composite: ["studentNumber", "schoolYear", "yearLevel", "section"]
        ...
    }
}

Let say, On the schoolYear: "2014-2015", a certain yearLevel: 1 student with studentNumber: "2011-488-MN-0" transferred section from section: "1D" to section: "1N". Now to perform this record update, we do something similar inside a service:

StudentHistory record = StudentHistory.find {
    eq("studentNumber", "2014-488-MN-0")
    eq("schoolYear", "2014-2015")
    eq("yearLevel", 1)
    eq("section", "1D")
}

record.setSection("1N")

record.save(flush: true, insert: false)

The problem is that the update on the primary key doesn't take effect but when I tried to update other non-Primary fields such as average and status, updating them works fine (I tried performing an SQL directly on the database to confirm). How can I update primary keys?


PS: Now, based on this design, I know some will suggest that why not just create another record, then just fetch the record that has been last entered? But what I am required to do is to update that composite primary key instead.


PPS: Please don't suggest on removing the old instance, and create a new one, copying the old details except for the section. I cannot do that since many tables are connected to this table.


Solution

  • I believe it is a good practice to avoid changing primary keys. Primary key is a unique identifier of an object and changing it effectively means creating a new object. So if your composite primary key is mutable (or can mutate) then you should use a surrogate key - an artificial primary key. At the same time you can create a unique constraint on the 4 fields currently being your primary key.

    In your case it would be:

    static mapping = {
       ...
    }
    
    static constraints = {
       studentNumber(unique: ["schoolYear", "yearLevel", "section"])
    }
    

    Hope it makes sense.