[Sqlalchemy-tickets] Issue #3230: Overlapping Composite Keys confuse the Dependency Rule (zzzeek/sq
Brought to you by:
zzzeek
|
From: nickretallack <iss...@bi...> - 2014-10-18 00:39:47
|
New issue 3230: Overlapping Composite Keys confuse the Dependency Rule https://bitbucket.org/zzzeek/sqlalchemy/issue/3230/overlapping-composite-keys-confuse-the nickretallack: I see there was [already an issue about overlapping composite keys in the past](https://bitbucket.org/zzzeek/sqlalchemy/issue/2965/foreign_keys-logic-with-overlapping), but maybe mine's different, as this issue still exists in 0.9.8. The issue occurs when you try to un-relate some records with overlapping keys. Here's my example: ``` #!python from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, ForeignKey, Integer, String, ForeignKeyConstraint from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker, relationship Base = declarative_base() # Lets simulate a multi-tenant database system that doesn't use multiple schemas class Tenant(Base): __tablename__ = 'tenant' id = Column(Integer, primary_key=True) name = Column(String) # Something to be related to class Friend(Base): __tablename__ = 'friend' id = Column(Integer, primary_key=True) tenant_id = Column(ForeignKey('tenant.id'), primary_key=True) name = Column(String) tenant = relationship(Tenant) # Our model class Person(Base): __tablename__ = 'person' id = Column(Integer, primary_key=True) tenant_id = Column(ForeignKey('tenant.id'), primary_key=True) friend_id = Column(Integer) name = Column(String) __table_args__ = ( # friend relationship ForeignKeyConstraint( (friend_id, tenant_id), ('friend.id','friend.tenant_id'), ), ) tenant = relationship(Tenant) friend = relationship(Friend) engine = create_engine('sqlite:///:memory:', echo=True) Session = sessionmaker(bind=engine) def run(): # Basic Setup Base.metadata.create_all(engine) session = Session() # Make a person with a friend tenant = Tenant(name="testing", id=1) person = Person(name="Bob", tenant=tenant, id=1) friend = Friend(name="George", tenant=tenant, id=1) person.friend = friend session.add_all([tenant, person, friend]) session.commit() # Take away the friend person = session.query(Person).first() person.friend = None session.commit() # it tries to take away the tenant_id too, thus breaking the primary key if __name__ == '__main__': run() ``` When I run it, I get this: ``` AssertionError: Dependency rule tried to blank-out primary key column 'person.tenant_id' on instance '<Person at 0x105c05310>' ``` It shouldn't be blanking out the tenant_id, since that id still references the tenant. The relationship needs to know that, despite joining on a composite key here, only one of those columns is specific to this relationship. The other is shared with many other relationships. |