Renamed from to OoHasLimitedRelationalModeling.
Much of the ObjectRelationalImpedanceMismatch
problem is usually attributed to characteristics of the RelationalDatabase
, but what about characteristics of ObjectOriented
For the most part, the only intrinsic form of inter-instance association supported in OOP is a 1-way, pointer-like, named reference from one object to the other another. This causes problems when we need to map onto a storage model in which it is common to look at a single cross-reference from either side. It is fairly hard in current ObjectOriented
programming languages to reliably represent a network of objects that can be traversed in any direction from any starting point.
When an association in OOP is represented as separate reference from each side (as it often is), and then we interact with the RDNMS, there is always the problem of getting and keeping the in-memory references in sync, and making sure we don't have 2 objects representing the same stored tuple on the same side of a relationship, depending on which direction you're looking from e.g. a(1) -> b(1) and a(2) <- b(1) when both "a"s refer to the same stored tupple.
This situation can probably be improved by giving an OOP language a native, bidirectional object association mechanism that's navigable from either side. Since associations don't belong more to one class than another, they are defined outside of the classes, but they affect the behaviors of instances of the classes. If we do this, we have a network of associated entities that translates pretty cleanly and easily to/from the relational table schema underneath (though it is not itself a RelationalModel
nor intended to be one).
Class Employee < Role
Class Manager < Role
# Relation between Manager and Employee, seen as
# employees collection of Manager and as manager
# member of Employee.
Associate Manager#employees => (0..), Employee#manager => (0..1)
# Require junction objects for m-m since the association
# will usually need attributes of its own. Thus,
# "Associate Person#roles(0..) with # Role#people(0..)"
# would not be valid.
# Using a constant (n) association count is equivalent
# to a range from 0 to n, but the choice of form helps
# document programmer intent. Ranges must be from 0 to
# a constant or 0 to unlimited.
Associate Person#role_links => (0..), PersonRole#person => 1
Associate Role#person_links(0..) with PersonRole#role => 1
This code seems almost like the code we write in RubyOnRails
' Active Record!! May it be that the real issue here is lack of expressivity of main stream OO languages (C++, Java, C#). In Ruby we might even implement the Associate method! -- AurelianoCalvo
Does ActiveRecord guarantee consistency between has_many on one side and belongs_to on the other? In other words, would ActiveRecord prevent an instance of InvoiceLine referring to an instance of Invoice, where the Invoice has no corresponding member of invoice_lines, or has a reference to another object representing the same record, retrieved at a different time?
It would not prevent an instance of I
nvoiceLine referring to an instance of Invoice referring to an instance of Invoice, where the Invoice has no corresponding member of invoice_lines. What would happen (I haven't tested it) is that you will only be able to navigate the relation in one way. Even so, this is an ActiveRecord
limitation and not an object oriented one. It's feasible to implement Associate in Ruby, with just a minimum of syntax. It's just that DHH (the guy who implemented Rails) liked it the other way. A simple implementation (handling 1 to many associations) is 10 lines of code away of the ActiveRecord
library. Regarding the second part of the question ("or has a reference to another object representing the same record, retrieved at a different time?"), I don't see why is in any way related to this page, OoHasLimitedAssociationModeling
If the language were to include the concept of an association as opposed to a simple reference, then each view of the association would be consistent with the other by definition. An invoice line's existence in an invoice's .lines collection would be synonymous with the line's .invoice member referencing that same invoice. There would (from the programmer's perspectve) not be 2 different references corresponding to the same association, but 2 ends from which the single association can be seen and manipulated. Assigning invocie (a) to the .invoice property of a line (b) or adding the line (b) to the .lines collection of the invoice (a) would be synonymous actions.
If that's so important for you, just write the 10 lines of code missing and you will have support for "bidirectional references" in Ruby. The fact that no one written it yet as a library speaks of the lack of need. Or, may be, a lot of people are wrong. Just write the library and publish it as open source.
I know of one piece of software which attempts this in CeePlusPlus
. It is called OOFILE and can be referenced on the page of AndyDent
. -- JohnFletcher
See also: CantEncapsulateLinks