Question

I have the following Class Diagram for a grails application called Projects:

enter image Class Diagrammhere

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.

Was it helpful?

Solution

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.

OTHER TIPS

In this case, I would say that a 'best practice' is very much dependent on how your application will work, and the context that it is in. You could take either approach - I think the choice depends on answers to a few questions:

  • How many contracts will there be? As Felipe says, you could have performance problems by searching a single association.
  • Do you often want to separate contracts into types? If so, your approach may be better - even storing them on different tables. Be aware that if you store sub-classes on the same table, GORM/Hibernate will add a discriminator column so it can discriminate the types, which adds a small complication to the retrieval.
  • You might also consider doing explicit queries to retrieve only want you want from the database directly, instead of relying on GORMs association queries. If you had a lot of data, and wanted some kind of ordering or a subset, it may be better to do explicit queries (encapsulated in methods on Project) to get what you want.

So these are just a few things you might want to think about to decide what your 'best practice' is.

BTW, a small comment on your class diagram: since both Contract sub-classes reference a Timesheet, you could move that association up to Contract, and let them both inherit it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top