0

试图解决以下问题:

我有三个类,AABB如下所示:

class AB(Base):
    id = Column(Integer, primary_key=True)
    a_id = Column(Integer, ForeignKey('a.id'), nullable=False)
    a = relationship(
        'A', 
        cascade='save-update', 
        backref=backref(
            'abs', 
            cascade='save-update', 
            uselist=True
        )
    )
    b_id = Column(Integer, ForeignKey('b.id'), nullable=False)
    b = relationship(
        'B', 
        cascade='save-update', 
        backref=backref(
            'abs', 
            cascade='save-update', 
            uselist=True
        )
    )
    __tablename__ = 'ab'

class A(Base)
    id = Column(Integer, primary_key=True)
    __tablename__ = 'a'

class B(Base)
    id = Column(Integer, primary_key=True)
    __tablename__ = 'b'

A本质上,这是和之间的 m2m 关系Bid唯一不标准的是表中有一个列AB。它的存在是有原因的。

我想实现两个实例的“合并” A。我们得到a1a2。然后,在删除 之前a1,它与ABs 的所有关系都应该重新分配给a2。在流程中保留 的值至关重要(因此,实际上不应创建或删除AB.id的新实例)。AB

问题无论我如何尝试,每次我删除一个实例时A,SQLAlchemy 都会尝试用一个NULL值更新 foreign_key,从而打破NOT NULL约束。它通过发出明确的UPDATE ab SET a_id = NULL WHERE id = .... 即使我的程序中有以下循环,它也会这样做:

for ab in a1.abs:
    ab.a_id = a2.id
    session.db.add(ab)

session.db.delete(a1)

因此,在我看来,在发出 delete 之前,所有ab相关的 sa1都已安全移动到a2,但是出了点问题。

一些非解决方案

  • passive_deletes国旗。行为上的差异仅涉及那些尚未在内存中的行,这是不好的。
  • 添加delete级联对我来说风险很大。我想真正确保ab在合并过程中不会丢失任何对象。
  • 手动更新保存在关联中的列表似乎没有任何效果(UPDATE再次发布)。

非常感谢您的帮助!

4

2 回答 2

1

每当关系的内容与数据库中的实际行集之间存在同步问题时,我建议使用session.expire(). 下次访问数据时,它会强制从数据库中重新加载值。

关于过期和刷新:

http://docs.sqlalchemy.org/en/latest/orm/session.html#refreshing-expiring

关于集合中的陈旧数据:

http://docs.sqlalchemy.org/en/rel_0_8/orm/session.html#deleting-from-collections

这些功能救了我的命。现在,一切都按预期工作。此外,我可以通过sqlalchemy.sql.expressionAPI 进行批量更新,这通常更快,而不会牺牲 ORM 层中的数据完整性。

于 2013-08-29T01:03:04.780 回答
0

嗯……这里出了点问题。

“UPDATE ab SET a_id = NULL WHERE id = a1.id”应该影响 0 行,因为您已经更新了 ab.a_id = a1.id 的所有 ab。

因此只有一种可能的解释,您未能更新 ab。计算机往往不会说谎。我们有时只会错过他们的逻辑。

我的解决方案:为确保一切正常,在发出删除之前,找到所有指向 a1.id 的 ab 行,如果正如预期的那样,您至少找到一个,尝试了解为什么该行仍然存在。

也许 session.db.add(ab) 可以替换为 session.db.update(ab) 之类的东西,并且 add() 正在向您的 ab 表添加新行,或者如果不存在更新或您无法使用它,然后首先删除所有 ab where ab.a_id = a1.id 确保您已正确制作副本(我认为您有)

于 2013-08-27T15:54:34.367 回答