2010-06-14 7 views
36

Właśnie zaczął używać SQLAlchemy i uzyskać DetachedInstanceError i nie można znaleźć wiele informacji o tym miejscu. Używam instancji poza sesją, więc naturalne jest, że SQLAlchemy nie może załadować żadnych relacji, jeśli nie są one już załadowane, jednak atrybut, do którego uzyskuję dostępu, nie jest relacją, w rzeczywistości obiekt ten nie ma żadnych relacji. Znalazłem rozwiązania, takie jak szybkie ładowanie, ale nie mogę się do tego zastosować, ponieważ nie jest to relacja. Próbowałem nawet "dotknąć" tego atrybutu przed zamknięciem sesji, ale nadal nie zapobiega to wyjątkowi. Co może być przyczyną tego wyjątku dla właściwości niezwiązanej z relacjami nawet po pomyślnym uzyskaniu dostępu do niego raz? Pomoc w debugowaniu tego problemu jest doceniana. W międzyczasie spróbuję uzyskać powtarzalny samodzielny scenariusz i aktualizację tutaj.SQLAlchemy DetachedInstanceError regularne atrybutu (nie relacja)

Aktualizacja: To jest rzeczywista wiadomość wyjątek z kilku stosów:

File "/home/hari/bin/lib/python2.6/site-packages/SQLAlchemy-0.6.1-py2.6.egg/sqlalchemy/orm/attributes.py", line 159, in __get__ 
    return self.impl.get(instance_state(instance), instance_dict(instance)) 
    File "/home/hari/bin/lib/python2.6/site-packages/SQLAlchemy-0.6.1-py2.6.egg/sqlalchemy/orm/attributes.py", line 377, in get 
    value = callable_(passive=passive) 
    File "/home/hari/bin/lib/python2.6/site-packages/SQLAlchemy-0.6.1-py2.6.egg/sqlalchemy/orm/state.py", line 280, in __call__ 
    self.manager.deferred_scalar_loader(self, toload) 
    File "/home/hari/bin/lib/python2.6/site-packages/SQLAlchemy-0.6.1-py2.6.egg/sqlalchemy/orm/mapper.py", line 2323, in _load_scalar_attributes 
    (state_str(state))) 
DetachedInstanceError: Instance <ReportingJob at 0xa41cd8c> is not bound to a Session; attribute refresh operation cannot proceed 

częściowego modelu wygląda następująco:

metadata = MetaData() 
ModelBase = declarative_base(metadata=metadata) 

class ReportingJob(ModelBase): 
    __tablename__ = 'reporting_job' 

    job_id   = Column(BigInteger, Sequence('job_id_sequence'), primary_key=True) 
    client_id  = Column(BigInteger, nullable=True) 

a client_id pole jest, co jest przyczyną tego wyjątku z wykorzystanie jak poniżej:

Zapytanie:

jobs = session \ 
      .query(ReportingJob) \ 
      .filter(ReportingJob.job_id == job_id) \ 
      .all() 
    if jobs: 
     # FIXME(Hari): Workaround for the attribute getting lazy-loaded. 
     jobs[0].client_id 
     return jobs[0] 

To, co wywołuje wyjątek później z zakresu sesji:

 msg = msg + ", client_id: %s" % job.client_id 
+0

To może pomóc: http://stackoverflow.com/a/25694346/134904 – kolypto

Odpowiedz

53

znalazłem przyczynę podczas próby zawężenia kod, który spowodował wyjątek. Umieściłem ten sam kod dostępu atrybutu w różnych miejscach po zamknięciu sesji i stwierdziłem, że zdecydowanie nie powoduje żadnego problemu natychmiast po zamknięciu sesji zapytania. Okazuje się, że problem zaczyna się pojawiać po zamknięciu nowej sesji, która jest otwarta, aby zaktualizować obiekt. Kiedy zrozumiałem, że stan obiektu jest nieużyteczny po zamknięciu sesji, udało mi się znaleźć ten thread, który omawiał ten sam problem. Dwa rozwiązania, które pochodzą z wątku to:

  • Zachowaj sesję otwarte (co jest oczywiste)
  • Określ expire_on_commit=False do sessionmaker().

The 3rd opcją jest ręczne ustawienie expire_on_commit do False na sesji po jej utworzeniu, coś jak: session.expire_on_commit = False. Zweryfikowałem, że to rozwiązuje mój problem.

+4

byłoby 'session.expunge_all()' pomocy w ogóle? – Sardathrion

+0

Jak to pomaga? Wydaje się, że rzeczywiście kasuje sesję wszystkich załadowanych obiektów. – haridsv

+0

'session.expire_on_commit = False' jest złe, ponieważ jeśli baza danych przekonwertowała wartości na coś, nigdy się tego nie dowiesz – kolypto

8

Byliśmy coraz podobne błędy, nawet z zestawem do Falseexpire_on_commit. Ostatecznie spowodowało to, że oba urządzenia przyzwyczaiły się do sesji w różnych żądaniach. I naprawdę nie rozumiem, co się dzieje, ale jeśli widzisz ten wyjątek z expire_on_commit=False, upewnij się, że nie ma dwóch sessionmaker s zainicjowany.

0

Jak dla mnie (Newbie), zrobiłem błąd w tiret i zamknąć sesję w mojej pętli, w której pętla każdy wiersz, zrobić kilka operacji i zobowiązać się za każdym razem.

więc dla tych początkujących jak ja, sprawdź swój kod przed ustawieniem rzeczy jak expire_on_commit=False, może to prowadzić do innej swojej pułapki.

Powiązane problemy