Hi people,
I'm faced with a tough decision. Here is the problem: the way Elixir
generates/uses column names for bidirectional (ie where an inverse
exist), self-referencial ManyToMany relationships is buggy. To make
sure, here is an example of what I'm talking about:
class Person(Entity):
using_options(shortnames=True)
parents = ManyToMany('Person')
children = ManyToMany('Person')
Currently, it uses the following pattern for the columns of *all*
ManyToMany relationships:
"%(tablename)s_%(key)s"
In case the relationship is self-referential, it adds the "appearance
number" of the relationship (ie 1 for the first relationship declared,
and 2 for the inverse).
To illustrate this, the above example would generate a table with the
following columns: person_id1 and person_id2, the first one being used
by the "parents" side, while the second one is used for the "children"
side. The problem is that if you inverse the order of declaration of
those fields, the generated columns are the same but are used by the
other side of the relationship. In other words, the meaning of the
relationship is reversed.
Here are the solutions I could come up:
1) Produce column names which depend on the relation name for all
ManyToMany relationships.
Pro:
- Seems logical. This is the pattern I wish I had used in the first place.
Con:
- Massive breakage when upgrading from older Elixir: all ManyToMany
(self-referencial or not) relationships are affected. That is, each
developer will need to either:
* use old scheme through setting the global variable
"elixir.M2MCOL_NAMEFORMAT" before doing anything else with Elixir.
Ugly but effective.
* use local_colname AND remote_colname in every ManyToMany relationship.
* update all M2M tables
- We cannot easily detect (at Elixir-level) whether there is a
problem or not and thus provide "migration help" automatically. That
is, people upgrading without reading the release/upgrade notes (and
unfortunately I think most people don't) will be hit by strange
"missing column" errors without any clear indication of what to do to
fix the problem.
- Breaks if the relationship is renamed. This seems logical and IMO
acceptable. In that case, the developer can simply use local_colname
for the renamed relationship.
2) Assign col1 to the side of the relation with the "lowest"
(alphabetically speaking) name.
Pro:
- Much less breakage in upgrade from older Elixir: it will only
break bidirectional self-referential relationships. And only half of
them on average.
- Less breakage through relation renaming: it only breaks if a
relationship is renamed and the new name is different enough from the
old name that the alphabetic order (compared to the inverse
relationship) changes.
Con:
- When it breaks, it does so *silently*: it reverses the meaning of
the relationship. Even if there wouldn't be a lot of breakage, silent
breakeage is *not* acceptable IMO.
3) Add a (mandatory) argument to manually assign each side a number
"1" or "2", or a boolean argument to tell that one side is the "first"
one.
Pro:
- Only breaks self-referencial ManyToMany relationships.
- Easy and clear upgrade path.
Con:
- This seems extremely artificial.
- Still needs manual intervention during the upgrade.
4) Use a different pattern to generate columns for self-referential
relationships than for non self-referential (ie use solution #1 but
only for self-referential relationships).
Pro:
- Only breaks self-referencial ManyToMany relationships.
Con:
- No way to know there is a problem (see #1).
- A slight case of spaghetti code. But this is also true with the
current approach.
5) Any other idea?
Thanks for reading through all of this,
--
Gaƫtan de Menten
http://openhex.org
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"SQLElixir" 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/sqlelixir?hl=en
-~----------~----~----~----~------~----~------~--~---