On Aug 26, 2010, at 8:49 AM, Martin-Leon Francois wrote:

> hi,
> 
> The problem seems to be a little bit more general, I have a unique class 
> (doing nothing) mapped to a unique table.
> After opening a session, I create an instance, add it to the session, flush, 
> commit.
> Everything is ok. --> a row in the table, instance in the identity_map of the 
> session
> 
> Always in the same session, I delete the instance from the session., flush, 
> commit.
> Everything is ok. --> no row in the table, no  instance in the identity_map 
> of the session
> 
> Always the same session, I add again the python instance to the session, 
> flush, commit.
> ??? -->  no row in the table, instance in the identity_map of the session
> 
> Could you have a look to the code below and help me figure out what I doing 
> wrong?
> fma
> 
> #If I uncomment the following line (workaround) instance is written down to
> #the database as I would expect
> #o1._sa_instance_state = o1._sa_class_manager._create_instance_state(o1)
> 
> s.add(o1)
> s.add_all([o1])
> s.flush()
> s.commit()
> print list(s.query(One)), s.identity_map
> s.close()

OK this is a little strange.  o1 has been deleted.   You've found one 
particular operation that doesn't immediately raise (add()), but anything else 
you did with o1 would, for example:

        print o1.name

you will get this (since o1 is expired and will refresh, then fail):

        sqlalchemy.orm.exc.ObjectDeletedError: Instance '<One at 0x1288c70>' 
has been deleted.

as you've already figured out, o1 has state on it that tells SQLAlchemy that 
this object is already persistent - no INSERT will be executed again for the 
object.   The strange part here is that the object is beyond persistent and is 
in the deleted state, and we don't have an in-memory flag that would signal 
this, though perhaps that is called for here, I've never seen anyone trying to 
perform such an operation before.

Anyway to convert from persistent back to transient, use make_transient:
        
        from sqlalchemy.orm import make_transient
        make_transient(o1)

then the "key" is removed and the object is as though you just created it.

I want to check if there's some foolproof way we can block on add().

Also, the add()/add_all() calls are redundant as is the flush() right before 
the commit().


> 
> Le 26 août 2010 à 08:42, fma a écrit :
> 
>> Any suggestion helping solving this?
>> 
>> On 25 août, 13:02, Martin-Leon Francois <francois....@gmail.com>
>> wrote:
>>> Hi,
>>> 
>>> I am trying in the same  session to detach an instance from a collection ( 
>>> one to many)
>>> flush and commit everything (all is ok) and then attach the removed 
>>> instance  again. unsuccessfully.
>>> 
>>> in below code,  last "assert" fails.
>>> I don't understand why I am not able to append m2 to o1.to_many collection 
>>> once removed.
>>> 
>>> Any idea? ( I use sa 0.5.6)
>>> 
>>> thanx, Francois
>>> 
>>> meta = MetaData()
>>> tb_one = Table("one", meta,
>>>                Column('name',String(50)),
>>>                Column('id',Integer, primary_key=True))
>>> 
>>> tb_many = Table("many", meta,
>>>                Column('name',String(50)),
>>>                Column('id',Integer, primary_key=True),
>>>                Column('one_id', Integer, 
>>> ForeignKey(tb_one.c.id,ondelete='CASCADE'), nullable=False),)
>>> 
>>> class One(object):
>>>     def __init__(self, name):
>>>         self.name = name
>>> 
>>> class Many(object):
>>>     def __init__(self, name):
>>>         self.name = name
>>> 
>>> mapper_one = mapper(One,tb_one)
>>> mapper_many = mapper(Many, tb_many,
>>>                      properties = dict(
>>>                      to_one = relation(One,uselist=False, 
>>> backref=backref('to_many', cascade="save-update, merge, delete, 
>>> delete-orphan"),)))
>>> 
>>> engine = create_engine(....)
>>> Session = orm.sessionmaker(autoflush=True, autocommit=False, bind=engine)
>>> 
>>> meta.bind = engine
>>> meta.drop_all(checkfirst=True)
>>> meta.create_all(checkfirst=True)
>>> 
>>> s = Session()
>>> m1 = Many("M1")
>>> m2 = Many("M2")
>>> o1 = One("One")
>>> o1.to_many.append(m1)
>>> o1.to_many.append(m2)
>>> 
>>> s.add_all([m1,m2,o1])
>>> s.flush()
>>> s.commit()
>>> assert(len(o1.to_many) == 2)
>>> 
>>> o1.to_many.remove(m2)
>>> assert(len(o1.to_many) == 1)
>>> s.flush()
>>> s.commit()
>>> assert(len(o1.to_many) == 1)
>>> 
>>> o1.to_many.append(m2)
>>> assert(len(o1.to_many) == 2)
>>> s.flush()
>>> s.commit()
>>> assert(len(o1.to_many) == 2) #this assert fails why?
>>> 
>>> s.close()
>> 
>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "sqlalchemy" group.
>> To post to this group, send email to sqlalch...@googlegroups.com.
>> To unsubscribe from this group, send email to 
>> sqlalchemy+unsubscr...@googlegroups.com.
>> For more options, visit this group at 
>> http://groups.google.com/group/sqlalchemy?hl=en.
>> 
> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To post to this group, send email to sqlalch...@googlegroups.com.
> To unsubscribe from this group, send email to 
> sqlalchemy+unsubscr...@googlegroups.com.
> For more options, visit this group at 
> http://groups.google.com/group/sqlalchemy?hl=en.

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

Reply via email to