python - mapper_args - sqlalchemy polymorphic query




SQLAlchemy Inheritance (2)

Le choix de la représentation de l'héritage est principalement un problème de conception de base de données. Pour la performance, l'héritage de table unique 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 la table jointe est meilleur. L'héritage de tables jointes 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-classes. L'héritage de table concrète est un peu pire des deux mondes.

Configuration de l'héritage de table unique avec des déclarations déclaratives comme 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 l'associer à l'héritage de table, vous devez ajouter

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

aux sous-classes.

La requête 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 à considérer pour utiliser l'héritage pour le datamapping est de savoir si vous avez réellement besoin d'héritage ou si vous pouvez faire avec l'agrégation. L'héritage sera pénible si vous avez besoin de changer le type de bâtiment ou si 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 en tant qu'objets connexes.

Je suis un peu confus au sujet 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 certaines 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 est-ce que je convertirais ceci en SQLAlchemy en utilisant déclaratif? Comment, alors, je demander quels bâtiments sont dans x>5 et y>3 ? Ou quels bâtiments résidentiels ont seulement 1 résident?


Les fourmis La solution d'Aasma est beaucoup plus élégante, mais si vous conservez intentionnellement vos définitions de classe à part de vos définitions de tables, vous devez mapper vos classes à vos tables avec la fonction de mappeur. 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, interagir avec les classes de la même manière que décrit Ants Aasma.





sqlalchemy