【问题标题】:SQLAlchemy Cascade Delete (likely session confusion)SQLAlchemy 级联删除(可能会话混淆)
【发布时间】:2014-04-12 14:19:39
【问题描述】:

我试图在删除父级时将删除级联到子级。根据这个问题SQLAlchemy: cascade delete,我将cascade="all, delete-orphan" 选项添加到了孩子的backref 中。这在一定程度上似乎确实有效。子项实际上已从数据库中删除(通过 SQLlite 数据库浏览器确认),但子项仍然可见“python 端”:

代码:

class Product(Base):
    __tablename__ = 'products'
    id = Column(Integer, primary_key=True)
    product_name = Column(String(250), unique=True)
    vendor_id = Column(Integer, ForeignKey('vendors.id'), nullable=False)

    vendor = relationship('Vendor', backref = backref('products', order_by=id, cascade="all, delete-orphan"))

    def __init__(self, product_name, vendor_id):
        self.product_name = product_name
        self.vendor_id = vendor_id

    def __repr__(self):
        return '<Product: %r Product ID: %r Vendor ID: %r>' % (self.product_name, self.id, self.vendor_id)


class Module(Base):
    __tablename__ = 'modules'
    id = Column(Integer, primary_key=True)
    module_name = Column(String(250), unique=True)
    product_id = Column(Integer, ForeignKey('products.id'), nullable=False)

    product = relationship('Product', backref = backref('modules', order_by=id, cascade="all, delete-orphan"))

    def __init__(self, module_name, product_id):
        self.module_name = module_name
        self.product_id = product_id


    def __repr__(self):
        return '<Module: %r Module ID: %r Product ID: %r>' % (self.module_name, self.id ,self.product_id)

测试:

msg('Module Tests')
Product2Mod1 = Module('Product2Mod1',1)
Product2Mod2 = Module('Product2Mod2',1)
Product1Mod1 = Module('Product1Mod1',2)
Product1Mod2 = Module('Product1Mod2',2)
Product1Mod3 = Module('Product1Mod3',2)
db_session.add(Product2Mod1)
db_session.add(Product2Mod2)
db_session.add(Product1Mod1)
db_session.add(Product1Mod2)
db_session.add(Product1Mod3)
db_session.commit()
msg("Product2Mod1 Product:")
print Product2Mod1.product

msg('delete tests')

print "Query to show all products: \n"
print Product.query.all()

print "\nQuery to show all modules: \n"
print Module.query.all()

print "\ndeleting product 1: db_session.delete(Product1) --> db_session.commit()"
db_session.delete(Product1)
db_session.commit()
db_session.flush()

print "\nQuery to check for changes with products and modules (THIS IS CORRECT):\n"
print Product.query.all()
print Module.query.all()

print "\nThe modules below belong to the deleted product, they should have disappeared (But they did not, THIS IS INCORRECT):"
print Product1Mod1
print Product1Mod2
print Product1Mod3

【问题讨论】:

    标签: python sqlite sqlalchemy


    【解决方案1】:

    实际上,SQLAlchemy 在这里的行为是正确的。要理解它,您必须远离 SQLAlchemy。您告诉图书馆删除其后端中的某些内容。但是,您仍然可以引用您自己创建并刚刚提供的实例。以这个人工示例为例:

    some_obj = MyClass()
    backend_storage.store(some_obj)
    backend_storage.delete(some_obj)
    

    您希望some_obj 现在在您的本地空间中会发生什么?这个库应该只删除你的变量吗?

    SQLAlchemy 的行为方式是这样的:它知道这些对象已经消失,因此询问它们不会再返回它们。但是,您仍然在本地拥有它们并且它们已经存在于那里,因此只要您对它们有引用,它们就会在内存中持久存在。

    还有一件事:这些对象是您自己创建的,还是由库返回的,都没有关系。他们现在是“你的”,现在外部代码应该搞砸了。例如:

    some_obj = backend_storage.load_one(MyClass)  # load the first object of MyClass
    backend_storage.delete(some_obj)
    

    这与上面相同:some_obj你的。如果您愿意,您甚至可以现在重新添加它,后端不会在意。

    【讨论】:

    • 那么这是否意味着在 SQLalchemy 中完全摆脱我需要做的事情 session.delete(some_obj) 然后 session.commit() 最后是 del some_obj?我只是很惊讶 ORM 没有为你这样做......这里的例子 SQLA example 似乎暗示你没有。
    • 您不必明确删除它们,只需停止使用它们即可。如果您在某处存储了引用(例如,在所有项目的全局列表中),那么您必须小心删除它们。如果您认为它类似于缓存,可能会有所帮助:您不希望 SQLAlchemy 从缓存中删除,对吗?关于这个例子:被删除的对象是'node1',如果你仔细看,任何地方都没有存储对它的引用。此外,SQLAlchemy 确实将其从自己的集合中删除(即node.children)。
    猜你喜欢
    • 2011-06-29
    • 2021-09-21
    • 2013-12-03
    • 1970-01-01
    • 2010-11-05
    • 1970-01-01
    • 1970-01-01
    • 2011-09-04
    • 2013-04-12
    相关资源
    最近更新 更多