Cox*_*oxy 5 python inheritance sqlalchemy
考虑使用联接继承的以下SQLAlchemy映射:
from sqlalchemy import sa
class Location(Base):
id = Column(Integer, primary_key=True)
name = sa.Column(sa.String)
type_ = sa.column(sa.String)
__tablename__ = 'location'
__mapper_args__ = {
'polymorphic_identity': 'location',
'polymorphic_on': type_,
}
class Field(Location):
id = Column(Integer, primary_key=True)
size = sa.Column(sa.Float)
__tablename__ = 'field'
__mapper_args__ = {
'polymorphic_identity': 'field',
}
__table_args__ = (
sa.ForeignKeyConstraint(['id'], ['location.id']),
)
session.query(Field).filter(Field.size < 5).delete()
Run Code Online (Sandbox Code Playgroud)
其中base是适当的声明性基础,session是适当的会话对象.上面的实现将导致删除Field对象而不删除父Location对象(因为文档解释清楚,query.delete()不支持继承).我可以通过session.delete(obj)使用ORM删除链中的对象来解决这个问题.但是,这会导致在数据库上执行n个 SQL删除语句(其中n是要删除的对象数).我有一个案例,我可能一次删除100,000个子对象的顺序,所以这个操作非常慢(假设我现在不可能不使用带有连接继承的ORM - 我太深了改变这个).
是否有内SQLAlchemy的任何结构或一个合理的选择,这将允许我传递查询类型的对象查询对象Field并适当地删除了项目Location表以及未做ň SQL语句删除?
注意,我目前正在使用PostgreSQL,但是希望保持解决方案db-agnostic.
编辑:根据请求添加表元数据和有关环境的更多信息.
经过一两个小时的尝试,我找到了一个代码不多的解决方案。然后我将复制它。
1.我检查了文档delete()。有两句话:
此方法不适用于连接继承映射,因为 SQL 不支持多表删除,并且继承映射器的连接条件不会自动呈现
和
然而,上述 SQL 不会从 Engineer 表中删除,除非在数据库中建立 ON DELETE CASCADE 规则来处理它。
简而言之,不要将此方法用于连接继承映射,除非您已采取额外的步骤来使其可行。
所以,定义一个外键约束是必要的。像这样:
class Location(Base):
__tablename__ = 'location'
id = Column(INTEGER, primary_key=True)
name = Column(VARCHAR(30))
type = Column(VARCHAR(30))
__mapper_args__ = {
'polymorphic_identity': 'location',
'polymorphic_on' : type,
}
class Field(Location):
__tablename__ = 'field'
id = Column(INTEGER, ForeignKey('location.id', ondelete='cascade'), primary_key=True)
size = Column(DECIMAL(20, 2))
__mapper_args__ = {
'polymorphic_identity': 'field',
}
Run Code Online (Sandbox Code Playgroud)
2.现在,如果我们删除Location, 中的行Field也会被删除。
session.query(Location).filter(Location.id == 1).delete()
Run Code Online (Sandbox Code Playgroud)
3.但是,发帖者不想删除FieldLocation。
session.query(Field).filter(Field.size < 5).delete()
Run Code Online (Sandbox Code Playgroud)
这仅删除行 inField而不删除 row in Location。因为Field是外表,所以不能级联主表。
所以,现在我们应该做的是从Location根据中删除Field.size < 5。
我努力了
session.query(Location).filter(Field.size < 5).delete()
Run Code Online (Sandbox Code Playgroud)
和
session.query(Location).outerjoin(Field, Location.id == Field.id).filter(Field.size < 5).delete()
Run Code Online (Sandbox Code Playgroud)
这两个都会抛出异常。
经过多次尝试,我找到的解决方案是这样的:
statment = delete(Field, prefixes=[Location.__tablename__]).where(Field.size == 1)
session.execute(statment)
Run Code Online (Sandbox Code Playgroud)
生成的sql是DELETE location FROM location JOIN field ON location.id = field.id WHERE field.size < 5
| 归档时间: |
|
| 查看次数: |
431 次 |
| 最近记录: |