The new system I’m starting has several domains that are just join tables for many-to-many relations. They are all like this example for Spring Security Core. In the case, of Spring Security, a “legacy” database is being mapped, so using a composit key is necessary.
My question is if it’s possible to put a unique constraint on the combination of the fields instead of having to use a composite key and thus having to implement the get and other functions. I’d be quite happy to use the id as the key, but I do need to ensure the records are unique.
In other words, how could I add a unique constraint on secUser + secRole instead of creating a composite key in the following domain?
class SecUserSecRole implements Serializable {
SecUser secUser
SecRole secRole
boolean equals(other) {
if (!(other instanceof SecUserSecRole)) {
return false
}
other.secUser?.id == secUser?.id &&
other.secRole?.id == secRole?.id
}
int hashCode() {
def builder = new HashCodeBuilder()
if (secUser) builder.append(secUser.id)
if (secRole) builder.append(secRole.id)
builder.toHashCode()
}
static SecUserSecRole get(long secUserId, long secRoleId) {
find 'from SecUserSecRole where secUser.id=:secUserId and secRole.id=:secRoleId',
[secUserId: secUserId, secRoleId: secRoleId]
}
static SecUserSecRole create(SecUser secUser, SecRole secRole, boolean flush = false) {
new SecUserSecRole(secUser: secUser, secRole: secRole).save(flush: flush, insert: true)
}
static boolean remove(SecUser secUser, SecRole secRole, boolean flush = false) {
SecUserSecRole instance = SecUserSecRole.findBySecUserAndSecRole(secUser, secRole)
if (!instance) {
return false
}
instance.delete(flush: flush)
true
}
static void removeAll(SecUser secUser) {
executeUpdate 'DELETE FROM SecUserSecRole WHERE secUser=:secUser', [secUser: secUser]
}
static void removeAll(SecRole secRole) {
executeUpdate 'DELETE FROM SecUserSecRole WHERE secRole=:secRole', [secRole: secRole]
}
static mapping = {
id composite: ['secRole', 'secUser']
version false
}
}
You could do that if you’re allowed to add a new column that’ll be the real primary key, e.g. an autoincrement or a sequence-based column. Then adding the unique constraint would be simple:
But I doubt that’s an option 🙂
Note that Grails 2.0 has support for Hibernate Bags, which addresses the collection performance problems that this SecUserSecRole approach works around.