2016-11-18 26 views
8

aplikacja My SQLAlchemy (działa na szczycie MariaDB) obejmuje dwa modele MyModelA i MyModelB gdy ta ostatnia jest dziecko-zapis były:Błąd w wycofywaniu SQLAlchemy po wyjątku DB?

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) 

Są to przypadki MyModelA i MyModelB że tworzę:

>>> my_a = MyModelA(my_field1="A1") 
>>> my_a.aid 
1 
>>> MyModelB(a_id=my_a.aid, my_field2="B1") 

mam następujące kod, który usuwa wystąpienie MyModelA gdzie a_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() 

Kiedy uruchomić ten kod obejrzenia nieoczekiwanych wyników uzyskać:

#1) Number of MyModelAs: 1 
#2) Cannot delete instance of MyModelA because it has child record(s)! 
#3) Number of MyModelAs: 0 

Delete podobno nie powiedzie się i DB zgłasza wyjątek, który powoduje wycofywanie. Jednak nawet po wycofaniu liczba wierszy w tabeli wskazuje, że wiersz - który rzekomo nie został usunięty - faktycznie zniknął !!!

Dlaczego tak się dzieje? Jak mogę to naprawić? Wygląda jak błąd w SQLAlchemy.

+0

Czy sprawdziłeś, czy autocommit jest wyłączony? –

+0

sam pomysł: mówisz, że używasz MariaDB. Który silnik w MariaDB? MyISAM nie obsługuje transakcji, więc zawsze jest w trybie "autocommit". –

+0

Jakie są zapytania generowane przez sqlalchemy? Czy 'SELECTs' mają' DO AKTUALIZACJI '? –

Odpowiedz

0

TL; DR Twój problem może być związany z brakiem jawnej deklaracji relacji.

Na przykład here znajduje się próbka relacji obiektów. Oprócz użycia pola ForeignKey, klasa jawnie używa dyrektywy relationship do zdefiniowania tego połączenia. W session API documentation, pojawi się następujący tekst:

odniesienia obiektu powinna być wykonana na poziomie obiektu, a nie na obcej kluczowego poziomu

Co może oznaczać na drodze SQLAlchemy do zarządzania relacjami. Nie jestem dogłębnie zaznajomiony z podstawowymi mechanizmami, ale możliwe, że tak właśnie się dzieje. Twoja sesja obejmuje tylko obiekt MyModelA. Ponieważ w definicji MyModelB nie zastosowano dyrektywy relationship(), obiekty typu MyModelA nie są świadome faktu, że niektóre inne obiekty mogą odwoływać się do nich poprzez ForeignKey. Dlatego też, gdy sesja ma zamiar zatwierdzić, nie jest świadoma faktu, że usunięcie obiektu wpływa na inny obiekt MyModelB, a jego mechanizm transakcji nie bierze tego pod uwagę. Sugeruję, że dodanie relacji jawnie może zapobiec temu zachowaniu.