You are missing a foreign key column in the "people" table that
corresponds to your Person->Company relation. As a result, SQLAlchemy
tries to use person.id as the foreign key column (because that column
happens to be a foreign key to a base table of Company) and everything
blows up.

So:
* Add a foreign key column to Person that refers to companies.id.
* Add a primaryjoin argument to your Persion.company relation, because
SQLAlchemy will now see two potential ways to get from Person to
Company (people.id -> bizentities.bizentity_id and people.company_id -
> companies.id) and refuse to guess which path to take. Try
"primaryjoin=lambda: Person.company_id == Company.__table__.c.id". I'm
using Company.__table__.c.id instead of Company.id because Company.id
maps to the "bizentities.bizentity_id" column and not the
"companies.id" column.

-Conor

On Sep 23, 11:16 am, Kevin Horn <kevin.h...@gmail.com> wrote:
> On Wed, Sep 23, 2009 at 10:57 AM, Kevin Horn <kevin.h...@gmail.com> wrote:
>
> > On Wed, Sep 23, 2009 at 12:27 AM, Michael Bayer 
> > <mike...@zzzcomputing.com>wrote:
>
> >> On Sep 22, 2009, at 11:59 AM, Kevin H wrote:
>
> >> > I'm having some trouble developing my model, and was hoping someone on
> >> > this list could help...
>
> >> > Here's what I want:
> >> > A BizEntity object
> >> > A Person and Company object (both descended from BizEntity, using
> >> > joined table inheritance)
> >> > A Company.employees attribute, which points to a list of Persons who
> >> > work for the company
> >> > A Person.company attribute, which points back to the company that
> >> > person works for
>
> >> > Whenever I try to combine inheritance with this sort of pseudo-
> >> > adjacency-list, I get really odd things happening when I try to query
> >> > from the tables...like getting the wrong company back when I query by
> >> > id.
>
> >> > Any ideas out there?  Anyone done something like this?
>
> >> I'm doing this.
>
> > Howdy, Michael!  Knowing that I'm not trying to do something impossible is
> > definitely a relief.
>
> >> The first thing to do is to definitely be on 0.5.6
> >> at the least.
>
> > OK, I'm on 0.5.5, so that's the first thing to fix, I guess.
>
> >> the next thing is to define the employees/company thing only once, as
> >> a relation/backref pair on just one of your mapped classes.   doing it
> >> twice will mess things up for sure.
>
> > Good to know, thanks.
>
> >> your example also mentions a table called "nodes" which from
> >> everything else mentioned below would be erroneous.   you don't need
> >> remote_side when mapping between Company and Person.
>
> > Wow, that's from something _really_ old.  Been commented out for a
> > while...I didn't even notice that.
>
> >> None of this would cause the wrong "Company" to come back from a
> >> simple query by id, though.   If that is really the effect you're
> >> seeing then something more fundamental might be amiss.
>
> > Looking at it again, it looks like this was caused by a problem in my
> > tests.  I was assuming something I shouldn't have been about the order of
> > the data I was testing.
>
> > Thanks for the pointers, I'll post back later with results.
>
> > Kevin Horn
>
> Still having problems...
>
> Here's my new model:
>
> # START OF MODEL
>
> Base = declarative_base()
>
> class BizEntity(Base):
>     __tablename__ = 'biz_entities'
>     id = Column('bizentity_id', Integer, primary_key=True)
>     type =  Column('bizentity_type', String(30), nullable=False)
>     __mapper_args__ = {'polymorphic_on': type}
>
> class Company(BizEntity):
>     __tablename__ = 'companies'
>     id = Column(Integer, ForeignKey('biz_entities.bizentity_id'),
> primary_key=True)
>     name = Column('company_name', String(50))
>     __mapper_args__ = {'polymorphic_identity': 'company'}
>
>     def __init__(self, company_name):
>         self.name = company_name
>
>     def __repr__(self):
>         return "<Company('%s')>" % (self.name)
>
> class Person(BizEntity):
>     __tablename__ = 'people'
>     id = Column('bizentity_id', Integer,
> ForeignKey('biz_entities.bizentity_id'), primary_key=True)
>     first_name = Column('first_name', String(50))
>     middle_init = Column('middle_init', String(1))
>     last_name = Column('last_name', String(50))
>
>     company = relation(Company, backref=backref('employees', order_by=id))
>
>     __mapper_args__ = {'polymorphic_identity':'person'}
>
>     def __init__(self, first_name, middle_init, last_name):
>         self.first_name = first_name
>         self.middle_init = middle_init
>         self.last_name = last_name
>
>     def __repr__(self):
>         return "<Person('%s %s. %s')>" % (self.first_name, self.middle_init,
> self.last_name)
>
> # END OF MODEL
>
> now when I try to use it like this:
>
> # START SAMPLE CODE
>         comp1 = Company('Test Company')
>         #~ self.session.add(comp1)
>         #~ self.session.commit()
>
>         joe = Person('Joe', 'Q', 'Public')
>         joe.company = comp1
>         self.session.add(joe)
>
>         self.session.commit()
> # END SAMPLE CODE
>
> I get a traceback like this:
>
> Traceback (most recent call last):
>   File "ta_sa_test.py", line 98, in testCreateCompanyWithEmployees
>     self.session.commit()
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\session.py",
> line 673, in commit
>     self.transaction.commit()
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\session.py",
> line 378, in commit
>     self._prepare_impl()
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\session.py",
> line 362, in _prepare_impl
>     self.session.flush()
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\session.py",
> line 1356, in flush
>     self._flush(objects)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\session.py",
> line 1434, in _flush
>     flush_context.execute()
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\unitofwork.py",
> line 261, in execute
>     UOWExecutor().execute(self, tasks)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\unitofwork.py",
> line 753, in execute
>     self.execute_save_steps(trans, task)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\unitofwork.py",
> line 773, in execute_save_steps
>     self.execute_cyclical_dependencies(trans, task, False)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\unitofwork.py",
> line 789, in execute_cyclical_dependencies
>     self.execute(trans, [t], isdelete)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\unitofwork.py",
> line 753, in execute
>     self.execute_save_steps(trans, task)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\unitofwork.py",
> line 773, in execute_save_steps
>     self.execute_cyclical_dependencies(trans, task, False)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\unitofwork.py",
> line 789, in execute_cyclical_dependencies
>     self.execute(trans, [t], isdelete)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\unitofwork.py",
> line 753, in execute
>     self.execute_save_steps(trans, task)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\unitofwork.py",
> line 768, in execute_save_steps
>     self.save_objects(trans, task)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\unitofwork.py",
> line 759, in save_objects
>     task.mapper._save_obj(task.polymorphic_tosave_objects, trans)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\mapper.py",
> line 1406, in _save_obj
>     c = connection.execute(statement.values(value_params), params)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\engine\base.py",
> line 824, in execute
>     return Connection.executors[c](self, object, multiparams, params)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\engine\base.py",
> line 874, in _execute_clauseelement
>     return self.__execute_context(context)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\engine\base.py",
> line 896, in __execute_context
>     self._cursor_execute(context.cursor, context.statement,
> context.parameters[0], context=context)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\engine\base.py",
> line 950, in _cursor_execute
>     self._handle_dbapi_exception(e, statement, parameters, cursor, context)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\engine\base.py",
> line 931, in _handle_dbapi_exception
>     raise exc.DBAPIError.instance(statement, parameters, e,
> connection_invalidated=is_disconnect)
> IntegrityError: (IntegrityError) PRIMARY KEY must be unique u'INSERT INTO
> biz_entities (bizentity_id, bizentity_type) VALUES (?, ?)' [1, 'person']
>
> and if I enable the commented-out lines in my sample code, I get a traceback
> like this:
>
> Traceback (most recent call last):
>   File "ta_sa_test.py", line 98, in testCreateCompanyWithEmployees
>     self.session.commit()
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\session.py",
> line 673, in commit
>     self.transaction.commit()
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\session.py",
> line 378, in commit
>     self._prepare_impl()
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\session.py",
> line 362, in _prepare_impl
>     self.session.flush()
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\session.py",
> line 1356, in flush
>     self._flush(objects)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\session.py",
> line 1434, in _flush
>     flush_context.execute()
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\unitofwork.py",
> line 261, in execute
>     UOWExecutor().execute(self, tasks)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\unitofwork.py",
> line 753, in execute
>     self.execute_save_steps(trans, task)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\unitofwork.py",
> line 773, in execute_save_steps
>     self.execute_cyclical_dependencies(trans, task, False)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\unitofwork.py",
> line 789, in execute_cyclical_dependencies
>     self.execute(trans, [t], isdelete)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\unitofwork.py",
> line 753, in execute
>     self.execute_save_steps(trans, task)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\unitofwork.py",
> line 773, in execute_save_steps
>     self.execute_cyclical_dependencies(trans, task, False)
>   File
> "C:\Python26\lib\site-packages\sqlalchemy-0.5.6-py2.6.egg\sqlalchemy\orm\unitofwork.py",
> line 789, in...
>
> read more »
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to