On Jul 14, 2010, at 1:57 PM, Nikolaj wrote:

> I'm using consecutive merge() calls to fetch the same persistent
> instance from the Session.
> The test case below works as I expected: the first get_item() issues a
> SELECT, the second issues an UPDATE, the third does neither.
> 
> However, in my large project, using the pattern below (without the
> attribute modification) seems to issue a SELECT for every call to
> merge(). I'm trying to diagnose why this is happening but can't see
> anything obviously wrong like committing between calls or anything.
> 
> In what circumstances are instances removed from the Session's
> identity map? Is there somewhere I can read more about the internals
> of this so I can gain a better understanding of the Session?

In the program you have below, your Item gets expired after the commit(), so 
the SELECT is emitted to refresh it later on.

instances are removed as soon as all strong references to them on the outside 
are removed, provided those instances are persistent and have no pending 
changes.   If you are at the start of some long series of operations involving 
a large set of objects, its typical to load the ones you want to stay around 
into a set or dictionary of some kind, then call into the start of the 
operation.  Usually when im merging, I'm merging things based on a "name" field 
but there is a surrogate key, so i do something like this:

lookup = dict(Session.query(Foo.name, Foo))
do_my_thing(lookup)

def do_my_thing(lookup):
   for obj in someplace_i_get_objects():
        if obj.name in lookup:
            obj.id = lookup[obj.name].id
        obj = Session.merge(obj)

but again if your issue is just that commit() is expiring rows, and you'd like 
to hold onto what you loaded from the previous transaction, set 
expire_on_commit=False (or just dont commit() in the middle of a series of 
operations, probably the better idea).


> 
> ---
> 
> from sqlalchemy import create_engine, Column
> from sqlalchemy.ext.declarative import declarative_base
> from sqlalchemy.orm import scoped_session, sessionmaker
> from sqlalchemy.types import Integer, String
> 
> engine = create_engine('sqlite:///:memory:', echo=True)
> Base = declarative_base(bind=engine)
> Session = scoped_session(sessionmaker(bind=engine))
> 
> class Item(Base):
>    __tablename__ = 'items'
>    id = Column(Integer, primary_key=True)
>    name =  Column(String(50))
> 
> Base.metadata.create_all()
> 
> i = Item(id=1, name='Foo')
> Session.add(i)
> 
> Session.commit()
> 
> def get_item():
>    return Session.merge(Item(id=1))
> 
> one = get_item()
> print one.name
> 
> one.name = 'Bar'
> 
> two = get_item()
> print two.name
> 
> three = get_item()
> print three.name
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to 
> [email protected].
> 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 [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

Reply via email to