On Sep 4, 2014, at 6:58 PM, Ken Lareau <klar...@tagged.com> wrote:

> On Thu, Sep 4, 2014 at 3:30 PM, Michael Bayer <mike...@zzzcomputing.com> 
> wrote:
> 
> On Sep 4, 2014, at 5:37 PM, Ken Lareau <klar...@tagged.com> wrote:
> 
>> So I have a few tables as follows (abbreviated for unnecessary columns):
>> 
>> class Project(Base):
>>     __tablename__ = 'projects'
>> 
>>     id = Column(u'project_id', INTEGER(), primary_key=True)
>> 
>>     applications = relationship(
>>         'AppDefinition',
>>         secondary=lambda: Base.metadata.tables['project_package'],
>>         passive_deletes=True,
>>         lazy=False,
>>     )
>> 
>>     package_definitions = relationship(
>>         'PackageDefinition',
>>         secondary=lambda: Base.metadata.tables['project_package'],
>>         passive_deletes=True,
>>     )
>> 
>> 
>> class PackageDefinition(Base):
>>     __tablename__ = 'package_definitions'
>> 
>>     id = Column(u'pkg_def_id', INTEGER(), primary_key=True)
>> 
>>     applications = relationship(
>>         'AppDefinition',
>>         secondary=lambda: Base.metadata.tables['project_package'],
>>         passive_deletes=True,
>>     )
>> 
>>     projects = relationship(
>>         'Project',
>>         secondary=lambda: Base.metadata.tables['project_package'],
>>         passive_deletes=True,
>>     )
>> 
>> 
>> class AppDefinition(Base):
>>     __tablename__ = 'app_definitions'
>> 
>>     id = Column(u'AppID', SMALLINT(display_width=2), primary_key=True)
>> 
>>     package_definitions = relationship(
>>         'PackageDefinition',
>>         secondary=lambda: Base.metadata.tables['project_package'],
>>         passive_deletes=True,
>>     )
>> 
>>     projects = relationship(
>>         'Project',
>>         secondary=lambda: Base.metadata.tables['project_package'],
>>         passive_deletes=True,
>>     )
>> 
>> 
>> class ProjectPackage(Base):
>>     __tablename__ = 'project_package'
>> 
>>     project_id = Column(
>>         INTEGER(),
>>         ForeignKey('projects.project_id', ondelete='cascade'),
>>         primary_key=True
>>     )
>>     pkg_def_id = Column(
>>         INTEGER(),
>>         ForeignKey('package_definitions.pkg_def_id', ondelete='cascade'),
>>         primary_key=True
>>     )
>>     app_id = Column(
>>         SMALLINT(display_width=6),
>>         ForeignKey('app_definitions.AppID', ondelete='cascade'),
>>         primary_key=True
>>     )
>> 
>>     app_definition = relationship('AppDefinition', uselist=False)
>>     package_definition = relationship('PackageDefinition', uselist=False)
>>     project = relationship('Project', uselist=False)
> 
> this model has serious issues, though it can be made to hobble along with 
> some small changes.  The "three way association table" is not a great pattern 
> in the first place.  Additionally, using that same table as "secondary" in 
> all those places is clearly the issue here, and they don't even have 
> back_populates between them, which are used in many-to-many in order to try 
> avoid "double deleting".   But that wouldn't solve the issue here anyway.
> 
> As I feared, I figured this model would be frowned upon. :)  Note that this 
> model (or the underlying database)
> is not set in stone; if you have suggestions on a better way to link the 
> three main tables, I would love to hear
> it (and we did add back_populates (somehow missed them during the 
> restructuring of the models), but as
> you said, didn't help in this case).

A row in the 3-way table means that for this project_id, and pkg_def_id, and 
app_id, that's a single allowed value, so that's star schema, OK (though they 
call star schema "denormalized" - i don't exactly understand why, if you make 
all the columns part of the primary key).  But then you have functions that 
give you lists of things based on two-column slices of that table, in order to 
relate different dimensions to each other; projects->app_definitions, means you 
can have Project (X) -> AppDefnition(Y) any number of times, for every value of 
pkg_def_id.    I guess that's the awkward part here.   Those aren't really 
collection-based "relationships" so much as analytical queries across dimension 
tables.   They are valid queries but aren't really "object/relational" - when 
we map a class to another with a many-to-many collection in between, that means 
something more specific.

So maybe its just, object relational mapping assumes certain patterns are 
mappable to objects and collections, and 3-way associations aren't quite in 
that pattern :).    





-- 
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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to