On Jun 6, 2013, at 2:21 PM, Andy <[email protected]> wrote:

> I've written a handful of primaryjoin and secondaryjoin attributes on 
> Relationships.  This mechanism is flexible, but it's error-prone, and I think 
> that, at least for all the cases I've personally encountered, there could be 
> a better way.  As an example, I have:
> 
> thing = Table('thing', metadata,
>   Column('thing_id', Integer, primary_key=True),
>   Column('favorite_group_id', Integer),
>   ForeignKeyConstraint(['thing_id', 'favorite_group_id'], ['rel.thing_id', 
> 'rel.group_id'], use_alter=True, name='foobar'))
> 
> group = Table('group', metadata,
>   Column('group_id', Integer, primary_key=True))
> 
> rel = Table('rel', metadata,
>   Column('group_id', Integer, ForeignKey('group.group_id', primary_key=True),
>   Column('thing_id', Integer, ForeignKey('thing.thing_id'), primary_key=True))
> 
> IOW I have things and groups.  The rel table is a many-to-many relation 
> between things and groups.  A thing also may have a favorite group; if so, 
> there has to be a rel between that thing and its favorite group.  I don't 
> have a foreign key directly from favorite_group_id because the equivalent 
> constraint is already implied by the existing foreign keys.

that's a fascinating FK setup, took me a few minute to understand what i was 
looking at, but sure I see why it's that way.

> 
> Everything is straightforward to map, except the favorite_group relation on 
> thing -- there's no foreign key. 

well there is, it's to the primary key of your "rel" table.   If you were using 
the association pattern, then (I'm pretty sure) this would all work out 
naturally.

What you're doing here though is not mapping "rel" and then doing kind of an 
artificial primaryjoin over to "group" directly.   So this is exactly the 
reason primaryjoin exists, when you want to map "around" the normal linkages 
between tables.

> So I can set primary and primaryjoin, but here's a different suggestion:
> 
> Add a couple of flags to ForeignKeyConstraint so that I can have three kinds 
> of ForeignKeyConstraint:

OK you need to know that I really, really hate flags.  While we have lots of 
them, each one has arrived to the codebase in shame.   Flags mean that the 
normal construction of your objects is not good enough, you also have to deal 
with a big panel of switches that do strange things.   They make your API more 
complicated and mysterious.

>   ForeignKeyConstraint(['thing_id', 'favorite_group_id'], ['rel.thing_id', 
> 'rel.group_id'], use_alter=True, use_for_mapper=False, name='foobar'),

so this flag, is the most evil of all - it's a flag that explicitly leaks an 
ORM concept into the Core.   I think we are very close to having no leakage of 
explicit ORM concepts in the Core whatsoever at the moment (even in private 
APIs), but its a big library so I might be wrong.  But that's certainly a goal. 
  If we were to have hints that the ORM could understand inside of schema 
objects, it would be through some agnostic system like ForeignKeyContraint(, 
info={"orm": False}), or something like that (something better than that).

>   ForeignKeyConstraint(['favorite_group_id'], ['group.group_id'], 
> use_alter=True, emit_ddl=False, name='foobar'))
> 
> And now the trivial mapper relations will all work with no fiddling.

This flag at least is Core only but still, if emit_ddl is False then why do we 
need use_alter and name?  

> 
> Thoughts?

When a beginner comes to SQLAlchemy, and they want to make a custom join 
condition - now there are two entirely different ways of doing it.  Which one 
should they use and why ?   That's probably the biggest concern I have here.   
Two ways to do something means you have to produce the rationale for when to 
use each one.  

Not only that, but we are now placing ORM-specific configuration into our Table 
metadata.  What's wrong with doing it in relationship()?    Clearly, the way 
primaryjoin works, in that it's an expression, is cumbersome.   But that seems 
like a much easier problem to solve, just by adding some extra sugar to 
relationship itself?  Like relationship("MyTable", primaryjoin=[("a", "b"), 
("c", "d")])  ?   How is that more "fiddling" than the other approach?


-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to