我的sqlAlchemy应用程序(运行在mariadb之上)包括两个模型MyModelAMyModelB,后者是前者的子记录:

class MyModelA(db.Model):
    a_id   = db.Column(db.Integer, nullable=False, primary_key=True)
    my_field1 = db.Column(db.String(1024), nullable=True)

class MyModelB(db.Model):
    b_id   = db.Column(db.Integer, nullable=False, primary_key=True)
    a_id = db.Column(db.Integer, db.ForeignKey(MyModelA.a_id), nullable=False)
    my_field2 = db.Column(db.String(1024), nullable=True)

以下是我创建的MyModelAMyModelB的实例:
>>> my_a = MyModelA(my_field1="A1")
>>> my_a.aid
1
>>> MyModelB(a_id=my_a.aid, my_field2="B1")

我有以下代码删除MyModelAwherea_id==1的实例:
db.session.commit()
try:
    my_a = MyModelA.query.get(a_id=1)
    assert my_a is not None
    print "#1) Number of MyModelAs: %s\n" % MyModelA.query.count()
    db.session.delete(my_a)
    db.session.commit()
except IntegrityError:
    print "#2) Cannot delete instance of MyModelA because it has child record(s)!"
    db.session.rollback()
    print "#3) Number of MyModelAs: %s\n" % MyModelA.query.count()

当我运行此代码时,请查看我得到的意外结果:
#1) Number of MyModelAs: 1
#2) Cannot delete instance of MyModelA because it has child record(s)!
#3) Number of MyModelAs: 0

假设删除失败,数据库抛出一个导致回滚的异常。然而,即使在回滚之后,表中的行数也表明该行(假定没有被删除)实际上已经不存在了!!!!
为什么会这样?我怎么修这个?这看起来像是SQLAlchemy中的一个bug。

最佳答案


您的问题可能与缺乏明确的关系声明有关。
例如,here有一个对象关系示例。除了使用foreignkey字段之外,类还显式使用relationship指令来定义该连接。在session API documentation中,出现以下文本:
对象引用应在对象级别构造,而不是在外键级别构造。
这可能暗示了SQLAlchemy管理关系的方式。我对潜在的机制不太熟悉,但这可能就是发生的事情。您的会话只包括MyModelA对象。由于在relationship()的定义中没有使用MyModelB指令,MyModelA类型的对象不知道其他对象可能通过ForeignKey引用它们。因此,当会话即将提交时,它不知道删除对象会影响其他MyModelB对象,并且它的事务机制没有考虑到这一点。
我建议显式地添加关系可能会阻止这种行为。

08-20 02:45