当前位置: 首页 > 面试题库 >

当外键约束是组合主键的一部分时,依赖关系规则试图清除SQLAlchemy中的主键

齐铭
2023-03-14
问题内容

我有以下模型定义

class Foo(Base):
    __tablename__ = 'foo'

    id = Column(Integer, primary_key=True)
    name = Column(String(200))


class FooCycle(Base):
    __tablename__ = 'foocycle'

    foo_id = Column(
        String(50),
        ForeignKey('foo.id'),
        primary_key=True
    )
    some_number = Column(
        Integer,
        primary_key=True,
    )

    foo = relationship("Foo", backref="cycles")

和以下测试案例

class HierarchicModelTest(unittest.TestCase):
    def test_create_data_via_orm_save_twice(self):
        # get_session is a convenience wrapper to access a scoped session object
        s = get_session()

        def create_foo():
            foo = Foo(id="12345", name="fancy foo")
            foo.cycles = [FooCycle(some_number=1)]

            return foo

        # initially create foo
        foo = create_foo()
        s.add(foo)
        s.flush()

        # recreating foo, using merge to update into database
        foo = create_foo()
        s.merge(foo)

        # raises Exception: Dependency rule tried to blank-out primary key
        # column 'foocycle.foo_id' on instance '<FooCycle at 0x32e6b10>'
        s.flush()

测试失败,出现了一个干净的小堆栈跟踪和最终的声明错误,告诉我“依赖关系规则试图清除主键列’foocycle.foo_id”。我假设SQLAlchemy无法或不想在FooCycle本身上计算foo_id的值。我可以在create_foo以下位置自己明确设置此值:

def create_foo():
    foo = Foo(id="12345", name="fancy foo")
    foo.cycles = [FooCycle(some_number=1, foo_id="12345")]

    return foo

但是,由于简洁,架构方面的考虑以及个人的自尊心,我不想这么做。是否有一种简单的方法可以使SQLAlchemy解决此问题。我还没有完全掌握依赖规则的目的。关于这个问题的任何指示/信息吗?

堆栈跟踪:

# Test 1 of 7:
# test_core.HierarchicModelTest.test_create_data_via_orm_save_twice
===============
HierarchicModelTest: test_create_data_via_orm_save_twice (tests.test_core.HierarchicModelTest)
Failed test "test_create_data_via_orm_save_twice (tests.test_core.HierarchicModelTest)"! Reason: Dependency rule tried to blank-out primary key column 'foocycle.foo_id' on instance '<FooCycle at 0x39cda10>'
Traceback (most recent call last):
  File "/home/xxx/xxx/xxx/backend/tests/test_core.py", line 115, in test_create_data_via_orm_save_twice
    s.flush()
  File "/home/xxx/xxx/xxx/.env/lib/python2.7/site-packages/sqlalchemy/orm/scoping.py", line 149, in do
    return getattr(self.registry(), name)(*args, **kwargs)
  File "/home/xxx/xxx/xxx/.env/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 1879, in flush
    self._flush(objects)
  File "/home/xxx/xxx/xxx/.env/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 1997, in _flush
    transaction.rollback(_capture_exception=True)
  File "/home/xxx/xxx/xxx/.env/lib/python2.7/site-packages/sqlalchemy/util/langhelpers.py", line 57, in __exit__
    compat.reraise(exc_type, exc_value, exc_tb)
  File "/home/xxx/xxx/xxx/.env/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 1961, in _flush
    flush_context.execute()
  File "/home/xxx/xxx/xxx/.env/lib/python2.7/site-packages/sqlalchemy/orm/unitofwork.py", line 370, in execute
    rec.execute(self)
  File "/home/xxx/xxx/xxx/.env/lib/python2.7/site-packages/sqlalchemy/orm/unitofwork.py", line 479, in execute
    self.dependency_processor.process_saves(uow, states)
  File "/home/xxx/xxx/xxx/.env/lib/python2.7/site-packages/sqlalchemy/orm/dependency.py", line 552, in process_saves
    uowcommit, False)
  File "/home/xxx/xxx/xxx/.env/lib/python2.7/site-packages/sqlalchemy/orm/dependency.py", line 569, in _synchronize
    sync.clear(dest, self.mapper, self.prop.synchronize_pairs)
  File "/home/xxx/xxx/xxx/.env/lib/python2.7/site-packages/sqlalchemy/orm/sync.py", line 53, in clear
    (r, orm_util.state_str(dest))
AssertionError: Dependency rule tried to blank-out primary key column 'foocycle.foo_id' on instance '<FooCycle at 0x39cda10>'

问题答案:

根据van的评论,我能够找到解决方案。默认关系级联为"save-update, merge"。我必须将此设置为"save-update, merge, delete, delete-orphan"

单独添加delete并不能改变行为,这delete-orphan是必要的。

添加仅delete-orphan使删除测试用例失败,并带有问题中提到的“依赖关系规则”断言错误:

class HierarchicModelTest(unittest.TestCase):
    def test_delete_parent_object(self):
        foo = Foo(**foo_data).save()
        self.assertEqual(Foo.query.count(), 1)
        self.assertEqual(FooCycle.query.count(), 1)

        s = get_session()
        s.delete(foo)
        s.flush()

        self.assertEqual(Foo.query.count(), 0)
        self.assertEqual(FooCycle.query.count(), 0)

-

  File "/home/xxx/xxx/xxx/backend/tests/test_core.py", line 128, in test_delete_parent_object
     s.flush()
  [...]
  AssertionError: Dependency rule tried to blank-out primary key column 'foocycle.foo_id' on instance '<FooCycle at 0x37a1710>'

从SQLAlchemy文档中:

delete-orphan级联为级联添加了行为delete,这样子对象在与父对象解除关联时将被标记为删除,而不仅仅是父对象被标记为删除。

因此,FooCycle模型的正确定义是

class FooCycle(Base):
    __tablename__ = 'foocycle'

    foo_id = Column(
        String(50),
        ForeignKey('foo.id'),
        primary_key=True
    )
    some_number = Column(
        Integer,
        primary_key=True,
    )

    foo = relationship("Foo",
                       backref=backref("cycles",
                                        cascade="save-update, merge, "
                                                "delete, delete-orphan"))


 类似资料:
  • 问题内容: 一个表的外键是否可以成为另一个表的组合主键的一部分?例如,如果我有两个表,一个包含有关不同用户的所有活动项目的信息,另一个包含有关项目正在使用哪种设备的信息: 项目表: (两者都不是唯一的) 设备表: (两者都不是唯一的) 现在可以将设备表中的ProjectId设置为项目表中的外键吗?尝试时,我收到一条错误消息,指出“项目表”中的列与现有的主键或唯一约束不匹配? 问题答案: 不。 创建

  • 它应该允许独立地更新表,并在父行被删除时删除子行。

  • 我有一个表,有一个复合PK:Customer;我有一个视图,没有PK:Purchase 为了绑定我的实体,Hibernate强制我声明一个PK。所以我为购买创建了一个复合PK。 普切斯: 普查塞普克:

  • 问题内容: 我必须与Hibernate合作,但我不确定如何解决此问题,我有2个具有1..n关系的表,如下所示: 如何使用Hibernate进行管理? 我不知道如何声明将包含主键一部分的外键。 我的数据库架构是从Hibernate模型生成的。 问题答案: 我找到了解决此问题的两种方法。 第一个是一种解决方法,没有第二个那么整洁。 将实体的主键定义为包含,和的复合键,首先将假定为主键的内容定义为唯一约

  • 问题内容: 我试图弄清楚如何构建JPA实体bean,以使数据适用于我的设备。该数据库是旧的,一成不变的,所以我不能更改架构。设备模型具有复合主键,其中的一列是设备类型的FK。 我尝试了几种不同的方法。首先是设备具有DeviceModel和DeviceType,但是这给了我一个错误,那就是太多的东西在引用dev_type。因此,然后我尝试让DeviceModel引用DeviceType,但遇到了相同

  • 问题内容: 我有两个表,和。应该是不言自明的,并且包含所有变量的所有可能选择。 有一个外键,指出了它是哪个变量的选项。有一个外键,指出了当前选择的选项。 我用得到周围的循环关系上,并在“关系。但是,我想添加一个额外的数据库约束,以确保该约束是有效的(即,它所指的是一个引用它的选项)。 我需要的逻辑(假设它代表表中的一行)基本上是: 但是我不知道如何使用SQL,声明式或任何其他方法来构造这种约束。如

  • 问题内容: 我必须使用hibernate模式,并且不太确定如何解决此问题,我有2个具有1..n关系的表,如下所示: 我该如何使用Hibernate进行管理??? 我不知道如何管理第二张表的主键… 问题答案: 在Hibernate参考文档中有一个与您的案例完全相似的示例。在此示例之前,您将找到解释。这是与您的问题匹配的示例(用户是表A,客户是表B): 注意:如果您拥有这两个表的代理标识符,则要简单得

  • 无法添加或更新子行:外键约束失败(.,约束外键()引用()) 如果我删除,insert操作将会很好地工作。在将对象插入数据库之前,我检查了这些对象,并确保包含,包含。 用于创建和的SQL脚本为: Hibernate:创建表b(b_id integer not null auto_increment,string_results longtext,a_id integer,主键(b_id)) Hib