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.
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.