session.merge(p) will add a new object as “pending” if it does not exist in the 
database yet.  if it does exist, then it will be “persistent”.   within 
merge(), the session will emit an autoflush before it begins, so anything that 
is pending at that point will become persistent.  Within the merge itself, 
autoflush is set to false so that any queries within the process won’t trigger 
another autoflush.

Follow the demonstration below which illustrates this.   Also the talk I gave 
at 
http://techspot.zzzeek.org/2012/11/14/pycon-canada-the-sqlalchemy-session-in-depth/
 goes over this in detail.


from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class A(Base):
    __tablename__ = 'a'

    id = Column(Integer, primary_key=True)
    data = Column(String)

engine = create_engine("sqlite://", echo=True)
Base.metadata.create_all(engine)

s = Session(engine)

a1 = A(id=1, data='a1')
s.add(a1)
s.commit()
s.close()


s = Session(engine)

a1_persistent = A(id=1)
a2_pending = A(id=2)

# merge persistent.  autoflush, then it loads id=1 and
# populates.
a1_persistent_merged = s.merge(a1_persistent)

# it's marked as "dirty" because attributes were touched...
assert a1_persistent_merged in s.dirty

# but it actually has no net changes, so won't actually be flushed
assert not s.is_modified(a1_persistent_merged)

# but it is persistent.
assert inspect(a1_persistent_merged).persistent


# merge pending. autoflush, then it attempts to load id=2,
# doesn't find it, adds object to session.new
a2_pending_merged = s.merge(a2_pending)

# inspect reveals a2 is pending
assert inspect(a2_pending_merged).pending

# and is in .new
assert a2_pending_merged in s.new

# now it's not
s.flush()
assert a2_pending_merged not in s.new





On Feb 28, 2014, at 7:19 AM, Bao Niu <niuba...@gmail.com> wrote:

> As a follow-up question to my last post, could someone please explain a bit 
> why using session.add() would add a new item in session.new while using 
> session.merge() would add a new item in session.dirty? Even when the merge() 
> actually creates a new instance by querying the database?
> I thought merge() should cause the same effect as add() when it creates a new 
> instance in IdentitySet(). Why is there such a difference?
> 
> 
> On Wednesday, February 26, 2014 10:16:26 PM UTC-8, Bao Niu wrote:
> From my study of the documentation, it seems to be the case that the state of 
> "pending" refers to the set of instances that is the sum of both session.new 
> and session.dirty. Is this understanding correct?
> 
> In addition, using session.add() will almost always lead to a new item in 
> session.new, while using session.merge() will almost always lead to a new 
> item in session.dirty. For example, if I have an instance named p.
> 
> If I use session.add(p):
> >>>session.add(p)
> >>>session.new
> IdentitySet(([<__main__.P object at 0xb69fbc0c>])
> >>>session.dirty
> IdentitySet([])
> 
> If I use session.merge(p):
> >>>session.merge(p)
> >>>session.new
> IdentitySet([])
> >>>session.dirty
> IdentitySet(([<__main__.P object at 0xb69fbc0c>])
> 
> 
> So, the conclusion is: 
> session.add ==> a new item added to session.new
> session.merge ==> a new item added to session.dirty
> session.add + session.merge ==> "pending"
> 
> Is my conclusion correct?
> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to sqlalchemy+unsubscr...@googlegroups.com.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> Visit this group at http://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/groups/opt_out.

Attachment: signature.asc
Description: Message signed with OpenPGP using GPGMail

Reply via email to