ObjectDeletedError: Instance 'xxx' has been deleted

2,974 views
Skip to first unread message

sajuptpm

unread,
Nov 16, 2012, 7:31:50 AM11/16/12
to sqlal...@googlegroups.com

The code bellow throwing error "ObjectDeletedError: Instance 'xxx' has been deleted." when an exception throwing from "method1".

How fix this issue.


def main_method():
    DBSession.add(db_obj1)
    DBSession.fush()

    for x in lst:
        method1(db_obj1.id)


def method1(id):
    try:   
        s1 = DBSession()
        s1.begin_nested()

        db_obj2 = create_new_obj(id)
        DBSession.add(db_obj1)
        DBSession.fush()

        if some-codition:
            raise Exception("Failedd")

        s1.commit()
    except Exception, ex:
        s1.rollback()
        raise ex

sajuptpm

unread,
Nov 16, 2012, 7:42:53 AM11/16/12
to sqlal...@googlegroups.com


The code bellow throwing error "ObjectDeletedError: Instance 'xxx' has been deleted." when a exception throwing from "method1".
Eroor in line method1(db_obj1.id),  db_obj1.id failing.


How fix this issue.


def main_method():
    DBSession.add(db_obj1)
    DBSession.fush()

    for x in lst:
        try:
            method1(db_obj1.id)
        excpt Exception, ex:
            pass

Michael Bayer

unread,
Nov 16, 2012, 9:04:34 PM11/16/12
to sqlal...@googlegroups.com
this code is not written in a way that makes sense, as "db_obj2" is not referenced and it's not clear where "db_obj1" comes from inside of method1(). The use of DBSession.<method>() vs. s1.<method>() also suggests some details are being omitted here.

So without being able to tell what you're actually doing, the error means that you are attempting to refer to an attribute on an object (like my_object.some_attribute) after a transaction has been rolled back or committed, and the row to which my_object refers to no longer exists. This row might not exist because the transaction in which it was inserted was rolled back, or the row was deleted by a different transaction.

After a transaction ends, accessing an attribute on your object will re-emit a SELECT to the database in a new transaction.

Turning on echo=True or echo='debug' on your create_engine() can be a valuable tool in debugging exactly what is happening in your code, including the sequence of SELECT statements.


sajuptpm

unread,
Nov 17, 2012, 1:16:34 AM11/17/12
to sqlal...@googlegroups.com
H, Michael Bayer
Thanks

You are correct, the rollback in method1 rollbacking transaction in main_method.
I want to isolate
transaction in main_method from rollback in method1.

I attached more code.


from sqlalchemy.orm import scoped_session, sessionmaker
maker = sessionmaker(autoflush=True, autocommit=False,expire_on_commit=False,
                     extension=ZopeTransactionExtension())
zopelessmaker = sessionmaker(autoflush=True, \
                             autocommit=False, \
                             expire_on_commit=False)
DBSession = scoped_session(maker)



def main_method():
    db_obj1 = DBModelclass1("Hello")   
    DBSession.add(db_obj1)
    DBSession.fush()

    for x in lst:
        try:
            method1(db_obj1.id)
        excpt Exception, ex:
            pass



def method1(id):
    try:   

        s1 = DBSession()
        s1.begin_nested()
    db_obj2 = DBModelclass2("Test")
    db_obj2.refname = "name_%s" %(id)
        DBSession.add(db_obj2)

Michael Bayer

unread,
Nov 18, 2012, 2:22:20 AM11/18/12
to sqlal...@googlegroups.com
other than the typos, as well as the multiple calls to "method1()" for every "x" in a list where the "x" is apparently ignored, there is nothing obviously wrong with this code.  If you're using begin_nested(), it has to be on a platform that supports SAVEPOINT.  Currently Postgresql and MySQL with InnoDB are the two main platforms supported.

As I have already stated in my previous email, turning on echo=True and/or echo='debug' will illustrate the SQL being emitted as well as where transactions start and end.  This is a *critical* step to being able to understand your issue.  I'd also recommend using pdb so that you can step into the code and examine the state of the database and program state one line at a time.


Michael Bayer

unread,
Nov 18, 2012, 2:31:12 AM11/18/12
to sqlal...@googlegroups.com
your program as a working test case is attached, as well as the successful output. Feel free to experiment with this program to determine what causes your case to fail. Note that Postgresql, Oracle, MSSQL or MySQL with InnoDB is required for the SAVEPOINT to work. SQLite or MySQL with MyISAM will *not* work.


test.py
output.txt

sajuptpm

unread,
Nov 21, 2012, 6:51:37 AM11/21/12
to sqlal...@googlegroups.com
Hi, Michael Bayer.
Thanks, that example is really helpful.

In your example
I used Session.object_session method to verify that main_method and method1 running in two different sessions.
But my test result showing that
main_method and method1 running in same session.
I think, we can check this using method Session.object_session , I am not sure about that.

* added following code in main_method
    s1 = Session.object_session(db_obj1)
    print "=======main_method====session=====", vars(s1)

* added following code in method1
    s2 = Session.object_session(db_obj2)
    print "=======
method1====session=====", vars(s2)


Result
=========


=======main_method====session===== " {'autocommit': False, 'autoflush': True, 'transaction': <sqlalchemy.orm.session.SessionTransaction object at 0x22a5f90>, 'hash_key': 36330896, 'expire_on_commit': True, '_new': {}, 'bind': Engine(mysql://root:cvt@localhost/cvt_ee), '_deleted': {}, '_flushing': False, 'identity_map': {(<class '__main__.A'>, (1L,)): <sqlalchemy.orm.state.InstanceState object at 0x22a5c90>}, '_enable_transaction_accounting': True, 'extensions': [], '_identity_cls': <class 'sqlalchemy.orm.identity.WeakInstanceDict'>, 'twophase': False, '_Session__binds': {}, '_query_cls': <class 'sqlalchemy.orm.query.Query'>, '_mapper_flush_opts': {}}


=======method1====session===== {'autocommit': False, 'autoflush': True, 'transaction': <sqlalchemy.orm.session.SessionTransaction object at 0x2073190>, 'hash_key': 36330896, 'expire_on_commit': True, '_new': {}, 'bind': Engine(mysql://root:cvt@localhost/cvt_ee), '_deleted': {}, '_flushing': False, 'identity_map': {(<class '__main__.A'>, (2L,)): <sqlalchemy.orm.state.InstanceState object at 0x2073550>, (<class '__main__.A'>, (1L,)): <sqlalchemy.orm.state.InstanceState object at 0x22a5c90>}, '_enable_transaction_accounting': True, 'extensions': [], '_identity_cls': <class 'sqlalchemy.orm.identity.WeakInstanceDict'>, 'twophase': False, '_Session__binds': {}, '_query_cls': <class 'sqlalchemy.orm.query.Query'>, '_mapper_flush_opts': {}}



Reply all
Reply to author
Forward
0 new messages