Mam następujący model definicjeDependency zasada próbował pusty z klucza podstawowego w SQLAlchemy, gdy ograniczenie klucza obcego jest częścią kompozytowych klucz podstawowy
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")
i następujący przypadek testowy
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()
test kończy się niepowodzeniem z dokładnym niewielkim śladem stosu i ostatecznym błędem asercji, informującym mnie, że "reguła zależności próbowała wyzerować kluczową kolumnę klucza" foocycle.foo_id ". Zakładam, że SQLAlchemy nie może lub nie chce obliczyć wartości dla foo_id w samym FooCycle. Mogę jawnie ustawić tę wartość się w create_foo
:
def create_foo():
foo = Foo(id="12345", name="fancy foo")
foo.cycles = [FooCycle(some_number=1, foo_id="12345")]
return foo
Jednak, ze względu na zwięzłość, względów architektonicznych i wprawdzie osobistej dumy nie chce. Czy istnieje prosty sposób, aby SQLAlchemy rozwiązać ten problem. Nie całkiem zrozumiałem cel reguły zależności. Jakieś wskazówki/informacje na ten temat?
stosu Ślad:
# 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>'
Nie sądzę, jest to problem z SA nie jest w stanie obsłużyć 'foo_id'. W rzeczywistości jest to jeden z najlepszych punktów, w jaki SA jest w stanie to zrobić. Uważam, że problem polega na tym, że podczas "scalania" SA usuwam pierwszą instancję 'FooCycle' i wstawiam nową. Usunięcie pierwszego problemu jest problemem, ponieważ nie usuwa jego wiersza, a jedynie próbuje usunąć relację. Musisz skonfigurować odpowiednią regułę ['cascade'] (http://docs.sqlalchemy.org/en/rel_0_9/orm/relationships.html#sqlalchemy.orm.relationship.params.cascade) dla swojego związku. – van
Dzięki za komentarz, który skierował mnie we właściwym kierunku. – room2web
@van Czy mógłbyś nam powiedzieć, jaka jest właściwa * zasada kaskadowa w tym przypadku (najlepiej jako odpowiedź, jak sądzę, może to być zbyt wiele, aby zmieścić się w komentarzu)? Mówisz, że * nie usuwa swojego wiersza, ale próbuje jedynie usunąć relację *; ale jeśli wiersz zostanie usunięty, za każdym razem otrzymamy nowe wystąpienie 'FooCycle'. Czy istnieje sposób, aby zaktualizować SA już istniejące wiersze/wystąpienia "FooCycle" zamiast? –