2010-06-14 12 views
36

Ho appena iniziato a utilizzare SQLAlchemy e ottenere un DetachedInstanceError e non riesco a trovare molte informazioni su questo ovunque. Sto usando l'istanza al di fuori di una sessione, quindi è naturale che SQLAlchemy non sia in grado di caricare alcuna relazione se non sono già caricati, tuttavia l'attributo a cui sto accedendo non è una relazione, infatti questo oggetto non ha alcuna relazione. Ho trovato soluzioni come caricamento avido, ma non posso applicare a questo perché questa non è una relazione. Ho persino provato a "toccare" questo attributo prima di chiudere la sessione, ma non impedisce l'eccezione. Quale potrebbe essere la causa di questa eccezione per una proprietà non relazionale anche dopo che è stata acceduta con successo una volta prima? È gradito qualsiasi aiuto nel debug di questo problema. Nel frattempo cercherò di ottenere uno scenario autonomo riproducibile e di aggiornarlo qui.SQLAlchemy DetachedInstanceError con attributo regolare (non una relazione)

Update: Questo è il messaggio di eccezione effettivo con alcune pile:

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 

Il modello parziale è simile al seguente:

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) 

E la client_id campo è quello che sta causando questa eccezione con un utilizzo come di seguito:

Query:

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] 

Questo è ciò che fa scattare l'eccezione in seguito fuori del campo di applicazione della sessione:

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

Questo può aiutare: http://stackoverflow.com/a/25694346/134904 – kolypto

risposta

53

ho trovato la causa principale durante il tentativo di restringere il codice che ha causato l'eccezione. Ho inserito lo stesso codice di accesso all'attributo in posti diversi dopo la chiusura della sessione e ho scoperto che non causa alcun problema immediatamente dopo la chiusura della sessione di query. Risulta che il problema inizia a comparire dopo aver chiuso una nuova sessione che viene aperta per aggiornare l'oggetto. Una volta compreso che lo stato dell'oggetto è inutilizzabile dopo la chiusura di una sessione, sono riuscito a trovare questo thread che trattava lo stesso problema. Due soluzioni che vengono fuori del filo sono:

  • Mantenere una sessione aperta (che è ovvio)
  • Specificare expire_on_commit=False-sessionmaker().

Il 3 ° opzione è quella di impostare manualmente expire_on_commit-False sulla sessione, una volta che è stato creato, qualcosa di simile a: session.expire_on_commit = False. Ho verificato che questo risolva il mio problema.

+4

Sarebbe di aiuto 'session.expunge_all()'? – Sardathrion

+0

Come può essere d'aiuto? Sembra in realtà cancellare la sessione di tutti gli oggetti caricati. – haridsv

+0

'session.expire_on_commit = False' è sbagliato, poiché se il database ha convertito i valori in qualcosa, non lo saprai mai – kolypto

8

Abbiamo riscontrato errori simili, anche con expire_on_commit impostato su False. Alla fine è stato effettivamente causato dall'avere due sessionmaker s che si stavano entrambi abituando a fare sessioni in richieste diverse. Non capisco veramente cosa stia succedendo, ma se vedi questa eccezione con expire_on_commit=False, assicurati di non avere due sessionmaker inizializzati.

0

Per quanto riguarda me (newbie), ho commesso un errore sul rientro e ho chiuso la sessione all'interno del mio ciclo, in cui loopò ogni riga, eseguivo un'operazione e mi impegnavo ogni volta.

Quindi per i principianti come me, controlla il tuo codice prima di impostare cose come expire_on_commit=False, può portare a un'altra trappola.

Problemi correlati