2011-11-29 7 views
15

Mi aplicación permite a los usuarios crear y eliminar objetos Site. Lo he implementado usando session.add() y session.delete(). entonces tengo 'Guardar' y 'reset' botones que llaman session.commit() y session.rollback().La eliminación de un objeto a partir de una sesión de SQLAlchemy antes de que se haya persistido

Si agrego un nuevo Site, a continuación, guardar/cometerlo, y luego eliminarlo, todo va bien. Sin embargo, si trato de eliminar un objeto de la sesión antes de que se haya guardado, aparece el error "no persistido".

Código:

self.newSite = Site('foo') 
self.session.add(self.newSite) 
print self.session.new 
self.session.delete(self.newSite) 

Salida:

IdentitySet([<Site('foo')>]) 

Traceback (most recent call last): 
    File "C:\Program Files\Eclipse\dropins\plugins\org.python.pydev.debug_2.2.1.2011071313\pysrc\pydevd_comm.py", line 744, in doIt 
    result = pydevd_vars.evaluateExpression(self.thread_id, self.frame_id, self.expression, self.doExec) 
    File "C:\Program Files\Eclipse\dropins\plugins\org.python.pydev.debug_2.2.1.2011071313\pysrc\pydevd_vars.py", line 375, in evaluateExpression 
    result = eval(compiled, updated_globals, frame.f_locals) 
    File "<string>", line 1, in <module> 
    File "C:\Python27\Lib\site-packages\sqlalchemy\orm\session.py", line 1245, in delete 
    mapperutil.state_str(state)) 
InvalidRequestError: Instance '<Site at 0x1ed5fb0>' is not persisted 

entiendo lo que está pasando aquí, pero no estoy seguro de lo que debería estar haciendo en su lugar.

¿Hay algún otro método de eliminación de un objeto que aún no es persistido-de una sesión? ¿O debería llamar al session.flush() antes de intentar una eliminación, en caso de que el objeto que deseo eliminar aún no haya sido eliminado?

Si es el último, ¿cómo es que session.query() auto-flushes (asegurando que los objetos pendientes aparecen en los resultados de la consulta), pero session.delete() no (que aseguraría que los objetos pendientes puedan eliminarse sin error).

Respuesta

13

Puede Session.expunge() ella. Creo que la razón por la cual delete() es así es que te preocupa no estar al tanto de las cosas si lo envías pendiente. Pero puedo ver el otro lado de la historia sobre eso, lo pensaré. Básicamente, el estado implícito en delete() incluye algunas suposiciones de persistencia, pero probablemente no sean tan significativas como estoy pensando. Me viene a la mente un método de "borrar o eliminar", que es gracioso, básicamente, es el "guardar o actualizar" que originalmente copiamos de Hibernate, que simplemente se convirtió en "agregar". "add" puede hacer las transiciones de transient-> pending así como de detached-> persistent - ¿un potencial "remove()" haría ambas cosas pendientes-> transitorias y persistentes-> eliminadas? Lástima que la sesión con ámbito ya tiene "remove()" ....

Session.query() autoflujos porque está a punto de salir a la base de datos para emitir algunos SQL para obtener algunas filas; entonces lo que sea que tengas localmente debe salir primero. delete() simplemente marca el estado de un objeto, por lo que no es necesario invocar ningún SQL. Si quisiéramos que delete() trabaje en un pendiente, simplemente cambiaríamos esa afirmación.

Curiosamente, si rollback() es la sesión, lo que sea add() 'ed dentro de esa sesión, se borre o no, se elimina.

+3

Estoy de acuerdo con Mike que 'delete' podría ser más indulgente. Sin embargo, la situación actual se ha simplificado mucho: podría haber otros objetos relacionados que se hayan agregado explícita o implícitamente (a través de relaciones) a la misma sesión y no se hayan comprometido. Por lo tanto, IMO, la forma más limpia es hacer un 'rollback()' en la sesión. – van

+0

Gracias, eso tiene sentido ahora. Entonces, cuando se hace clic en el botón Eliminar, ¿cuál debería ser la lógica? Algo como 'try: session.delete (foo); excepto InvalidRequestError: session.expunge (foo) '? O, según [esta respuesta] (http://stackoverflow.com/a/3897845/665488), tal vez: 'if has_identity (foo): session.delete (foo); else: session.expunge (foo) '? –

+5

Probablemente diría "if object in session.new: expunge else: delete" – zzzeek

Cuestiones relacionadas