Héritage SQLAlchemy

Je suis un peu confus à propos de l'héritage sous sqlalchemy, au point où je ne suis même pas sûr du type d'héritage (table unique, table jointe, béton) que je devrais utiliser ici. J'ai une classe de base avec des informations partagées entre les sous-classes et des données complètement séparées. Parfois, je veux des données de toutes les classes, et parfois seulement des sous-classes. Voici un exemple:

class Building:
    def __init__(self, x, y):
        self.x = x
        self.y = y

class Commercial(Building):
    def __init__(self, x, y, business):
        Building.__init__(self, x, y)
        self.business = business

class Residential(Building):
    def __init__(self, x, y, numResidents):
        Building.__init__(self, x, y, layer)
        self.numResidents = numResidents

Comment convertir ceci en SQLAlchemy en utilisant declarative? Comment, alors, demanderais-je quels bâtiments se trouvent dans x>5 et y>3? Ou quels bâtiments résidentiels ont seulement 1 résident?

43
demandé sur Gringo Suave 2009-08-26 23:57:53

2 réponses

Choisir comment représenter l'héritage est principalement un problème de conception de base de données. Pour les performances, l'héritage d'une seule table est généralement le meilleur. D'un bon point de vue de la conception de la base de données, l'héritage de table joint est meilleur. L'héritage de table joint vous permet d'avoir des clés étrangères aux sous-classes appliquées par la base de données, il est beaucoup plus simple d'avoir des contraintes non nulles pour les champs de sous-classe. L'héritage de table en béton est un peu pire des deux mondes.

Configuration d'héritage de table unique avec déclaratif ressemble à ceci:

class Building(Base):
    __tablename__ = 'building'
    id = Column(Integer, primary_key=True)
    building_type = Column(String(32), nullable=False)
    x = Column(Float, nullable=False)
    y = Column(Float, nullable=False)
    __mapper_args__ = {'polymorphic_on': building_type}

class Commercial(Building):
    __mapper_args__ = {'polymorphic_identity': 'commercial'}
    business = Column(String(50))

class Residential(Building):
    __mapper_args__ = {'polymorphic_identity': 'residential'}
    num_residents = Column(Integer)

Pour qu'il soit joint à l'héritage de la table, vous devrez ajouter

__tablename__ = 'commercial'
id = Column(None, ForeignKey('building.id'), primary_key=True)

Aux sous-classes.

L'interrogation est la plupart du temps la même avec les deux approches:

# buildings that are within x>5 and y>3
session.query(Building).filter((Building.x > 5) & (Building.y > 3))
# Residential buildings that have only 1 resident
session.query(Residential).filter(Residential.num_residents == 1)

Pour contrôler les champs chargés, vous pouvez utiliser la méthode query.with_polymorphic().

La chose la plus importante à penser à l'utilisation de l'héritage pour le datamapping est de savoir si vous avez réellement besoin d'héritage ou si vous pouvez le faire avec l'agrégation. L'héritage sera une douleur si jamais vous en aurez besoin modifiez le type d'un bâtiment, ou vos bâtiments peuvent avoir des aspects commerciaux et résidentiels. Dans ces cas, il est généralement préférable d'avoir les aspects commerciaux et résidentiels comme objets connexes.

72
répondu Ants Aasma 2010-03-02 21:08:10

La solution de Ants Aasma est beaucoup plus élégante, mais si vous gardez intentionnellement vos définitions de classe séparées de vos définitions de table, vous devez mapper vos classes sur vos tables avec la fonction mapper. Après avoir défini vos classes, vous devez définir vos tables:

building = Table('building', metadata,
    Column('id', Integer, primary_key=True),
    Column('x', Integer),
    Column('y', Integer),
)
commercial = Table('commercial', metadata,
    Column('building_id', Integer, ForeignKey('building.id'), primary_key=True),
    Column('business', String(50)),
)
residential = Table('residential', metadata,
    Column('building_id', Integer, ForeignKey('building.id'), primary_key=True),
    Column('numResidents', Integer),
)

Ensuite, vous pouvez mapper les tables aux classes:

mapper(Building, building)
mapper(Commercial, commercial, inherits=Building, polymorphic_identity='commercial')
mapper(Residential, residential, inherits=Building, polymorphic_identity='residential')

Ensuite, interagissez avec les classes exactement de la même manière que fourmis Aasma décrit.

10
répondu adam 2009-08-27 12:19:07