I have the following Class Diagram for a grails application called Projects
:
Now I want to create the actual domain classes in grails. But I have an issue with that: I don't know how to map the associations in a "best practice" way. This is best explained by the example of a code implementation of the Project
domain class:
package com.pm.projects
class Project {
static hasMany = [contracts:Contract, customerContracts:CustomerContract, partnerContracts: PartnerContract]
String property1
Integer property2
Date property3
.
.
.
TypeN propertyN
static constraints = {
}
}
I have the feeling that it is bad practice to include all contract subclasses in the hasMany
map, because in an UML Class Diagram, subclasses inherit associations of their superclasses. Therefore, from a logical data model point of view, I feel like it would be leaner, clearer just to code:
static hasMany = [contracts:Contract]
Although this felt as the right approach in theory for myself, it turned out to make certain manipulation techniques of the data unavailable. For instance,
pro = Project.get(params.id)
ProPaconList = pro?.partnercontracts
ProCuconList = pro?.customercontracts
to create two lists of contracts, one for partnercontracts and another one for customercontracts.
Is it possible to achieve a similar result without including the subclasses in the hasMany
map? And even if yes, the more general Question would be: Can hasMany maps be compared to associations of UML Class Diagramms in a way that it is bad practice to "connect" a class not only with another independent class but also with this other class' subclasses?
I failed to find any information on this topic online, which is a shame because I am very interested in accurate data modelling following best practice and common conventions, not only trial and error.
You can map just like you felt right:
static hasMany = [contracts:Contract]
Then, if you want to get just the contracts of certain type, you can just create a method on the Project domain class to do so:
class Project {
static hasMany = [contracts:Contract]
def findPartnerContracts(){
return contracts.findAll { contract ->
contract.instanceOf( PartnerContract )
}
}
}
def pro = Project.get(params.id)
def proPaconList = pro?.findPartnerContracts()
I am not sure if this is a best practice, but... it is one way to do it.
Be careful with hasMany associations. If your collection tends to get big overtime, you might have performance issues. Take a look at this presentation by Burt Beckwith.