• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Polymorphic container hierarchies...

 
Eric Nielsen
Ranch Hand
Posts: 194
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I wasn't sure whether to put this is the design forum or here. I think my design is about right, but I can't figure out how to implement it in JPA (or underlying native hibernate).

My application focuses on handling registration for ballroom dance competitions. The simplest domain model would look something like

Event: A single competitive event. Most Competitions will have 10s to 100s of events.
Entry: A single registration of a Couple for an Event
Couple: The basic unit of registration, composed of two People in named roles (leader/follower)
Person: no explanation required

Event-1:M-Entries-M-1-Couple-M:2-Person

This would cover 95% of the cases. However there are other "units of registration" -- Team Match Teams (3-6 Couples form a single team, each couple has an assigned dance), Formation Teams (3-10 Couples, no specified ordering or role), and Production Number Squad (1+ People). I've been calling the superset of these "RegistrationEntities" -- I hate the term, since its outside the common domain language... but we don't have a term for this superset in the domain...

I was thinking about moving "Couple" outside of this hierarchy and introducing a "CoupleEntity" as one of the four direct subclasses. Thus CoupleEntity, TeamMatchTeam, and FormationTeam would all be able to re-use Couple(s) with the appropriate extra rules on cardinality,named roles, etc. See the attached diagram.

Two of the ManyToMany associations (betean FormationTeam and Couple, between ProductionNumberSquad and Person) can be regular bidirectional @ManyToMany. The TeamMatchTeam to Couple one needs an extra column, so will need to have an intermediate join entity.



Now the blue line stumps me -- this doesn't need to me a "real" association, but I need the equivalent functionality.
Ie, from a RegistrationEntity I can have a getMembers() abstract method, that the subclasses implement to return the set of People in that Entity. But I'm not sure how to go the other direction (which is the more important one) -- from a Person a I need a getRegistrationEntities. I don't need (nor particularly want) exposed "getCouples" nor "getProductionNumberSquads" (actually I do want a getCouples, but it should return only Couples that occur in CoupleEntities.... so its not the raw collection underlying the join of the Leader and Follower associations)

I had been playing with a version were I dropped "Couple" and all the RegistrationEntity subclasses and simply put in a "RegistrationEntityMembership" intermediate join table (regent_id, person_id, role). While I can get that system to work, that object model is so far removed from the real domain model everything else becomes painful.

Now the next approach I could try is to expose a getRawCouples() and getProductionNumberSquads() on Person (needed to allow proper bidirectional synchronization when adding a person to a couple, etc), and then build both a "getCouples" and a "getRegistrationEntities()" query from those primitive methods with suitable filtering... Of course the getCouples will be a highly used called, so I'll have to add some memoization, etc...

Is this the "right" way forward for this kind of model where we have a polymorphic collection type holding variable number of base units in subclass specific constraints and the base units needs a link back to all containers?
 
Geoff Hambrick
author
Greenhorn
Posts: 22
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It seems like it is an attribute (constraint) on a subtype of event whether it is for a single couple, teams, etc. The difference between each type of event manifests in the relationship to Couples and/or Teams that can register. You might call the target of the relationship "Entrant", which has Couple, Team, etc as subtypes. The reason you may want two hierarchies is to enable you to enforce the constraint. Otherwise, Teams could sign up for Couples only Events and vice versa.

Interestingly enough, rather than complicating things, it actually simplifies them a bit, as you can use the underlying datastore to help you enforce the constraint rather than do it in code.

Ok then, Geoff

For the "blue line", it is useful to think of the relationships on your object model as requirements for accessibility, so, if you need to be able to get from an Event to the individual Person(s), then there is a derived relationship shown on the diagram. At design time, you would likely exploit a honking big join in the underlying data store to come up with the list.
 
Eric Nielsen
Ranch Hand
Posts: 194
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Geoff Hambrick:
It seems like it is an attribute (constraint) on a subtype of event whether it is for a single couple, teams, etc. The difference between each type of event manifests in the relationship to Couples and/or Teams that can register. You might call the target of the relationship "Entrant", which has Couple, Team, etc as subtypes. The reason you may want two hierarchies is to enable you to enforce the constraint. Otherwise, Teams could sign up for Couples only Events and vice versa.

Interestingly enough, rather than complicating things, it actually simplifies them a bit, as you can use the underlying datastore to help you enforce the constraint rather than do it in code.


Yes, I have thought about having subtypes of Event. So far simply having an enum EventType on Event has been good enough for constraining the Entries. I haven't needed additional fields or polymorphic behavior (yet). Unless I'm missing something, it looks like the "Entrant" you mention is still my "RegistrationEntity" a with a possibly better name. I'm not seeing how the pair of hierarchies would allow me to enforce the constraint in the database, however.




For the "blue line", it is useful to think of the relationships on your object model as requirements for accessibility, so, if you need to be able to get from an Event to the individual Person(s), then there is a derived relationship shown on the diagram. At design time, you would likely exploit a honking big join in the underlying data store to come up with the list.

Can you comment a little more on this?

Within the Person entity, how would you map this (I guess read-only) collection?
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic