Joshua—
I've also struggled with the absence of polymorphic relationships. The short
answer is: 'no'. DataMapper does not provide a API for performing the sort of
n-table LEFT JOIN you describe. In fact, as far as I have seen, DataMapper does
not provide any API for producing a LEFT JOIN at all. However, this
'limitation' (design choice) can be worked around to a large degree.
First, some terminology: I would describe your Unit -> [Champion, Structure]
arrangement as a 'Class Table Inheritance' hierarchy. The join from Unit to
*one* of its several subtypes I have read described as an 'XOR join', though
I'm not sure how widely that term is used.
In 'Pragmatic SQL Antipatterns', Bill Karwin advocates precisely the structure
you presented as an alternative to polymorphic associations, and notes that
while you *can* (and likely should) enforce uniqueness of the :unit_id in both
the Champion and Structure descendants, SQL provides no facility to ensure that
a given :unit_id does not appear in more than one descendant table (ie., it is
incumbent on your application to ensure that a given :unit_id is unique among
Champion, Structure, and any other Unit subtypes).
An aside: I would go a step further than you expressed in your gist by setting
the Primary Key of the Champion and Structure tables as a Foreign Key into the
Unit table. This provides exactly the uniqueness constraint on :unit_id I
described in the preceding paragraph. Perhaps that was implied in your example,
I think it's worth pointing out specifically.
Down to your actual question: in my current project I 'cheated', and put a
:type column on the superclass (Unit) to facilitate easy querying in the case
of traversing from a single Unit to its descendant. This amounts to a bit more
complexity in the application logic, but the query itself becomes a simple
INNER JOIN. What I did is:
class Unit
property :id, Serial
property :type, Class
has 0..1, :champion
has 0..1, :structure
def descendant
case type
when Champion then self.champion
when Structure then self.structure
end
end
end
This implies that you have some manner of setting the Unit#type at an
appropriate time.
In the event you are querying for a collection of units and their descendants,
you can do the simpler thing and INNER JOIN Unit with each of its descendant
tables on :unit_id. If you've successfully preserved the uniqueness of a
:unit_id among the descendant tables, you will get the results you expect.
Hope this helps,
Emmanuel
On Jul 12, 2011, at 10:02 PM, Joshua Morris wrote:
> I wrote it up my question descriptively as I could in this gist:
> https://gist.github.com/1079730
>
> Asked in #datamapper but folks must've been busy, so I thought I'd try
> the list! :)
>
> Thanks in advance,
> -J. Morris
>
> --
> You received this message because you are subscribed to the Google Groups
> "DataMapper" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to
> [email protected].
> For more options, visit this group at
> http://groups.google.com/group/datamapper?hl=en.
>
--
You received this message because you are subscribed to the Google Groups
"DataMapper" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/datamapper?hl=en.