[sqlalchemy] session.add() vs session.merge() and delete child

2010-01-30 Thread avdd
I'm using session.add() to refresh my objects while working on them,
because I don't want to merge them with the persistent state.  But it
appears deletes aren't carrying across to child relations:


$ cat listdelete.py; python listdelete.py

import sqlalchemy as sql
from sqlalchemy import orm
from sqlalchemy.ext.declarative import declarative_base

echo = 0
engine = sql.create_engine(sqlite:///:memory:, echo=bool(echo))
metadata = sql.MetaData(bind=engine)
DB = orm.sessionmaker(bind=engine)
T = declarative_base(metadata=metadata)

class A(T):
__tablename__ = 'a'
id = sql.Column(sql.Integer, primary_key=True)
info = sql.Column(sql.String)
cc = orm.relation('C',
  backref='a',
  cascade='all,delete-orphan')
def __repr__(self):
return   a: %s cc=%s % (self.info, len(self.cc))

class C(T):
__tablename__ = 'c'
a_id = sql.Column(sql.Integer, sql.ForeignKey('a.id'),
primary_key=True)
i = sql.Column(sql.Integer, primary_key=True)

def get():
return DB().query(A).first()

def change(a, s, i):
orm.object_session(a).close()
db = DB()
db.add(a)
a.info = s
del a.cc[-1]
a.cc.append(C(i=i))
db.close()

metadata.create_all()
A.__table__.delete().execute()

db = DB()
a = A(id=1, info='blah', cc=[C(i=1), C(i=2)])
db.add(a)
db.commit()
db.close()

print get()

# merge and flush
a = get()
change(a, 'change one', 3)
db = DB()
db.merge(a)
db.commit()
db.close()

print get()

# add and flush
a = get()
change(a, 'change two', 4)
db = DB()
db.add(a)
db.commit()
db.close()

print get()


  a: blah cc=2
  a: change one cc=2
  a: change two cc=3

-- 
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.



Re: [sqlalchemy] session.add() vs session.merge() and delete child

2010-01-30 Thread Michael Bayer

On Jan 30, 2010, at 9:07 AM, avdd wrote:

 I'm using session.add() to refresh my objects while working on them,
 because I don't want to merge them with the persistent state.  But it
 appears deletes aren't carrying across to child relations:

this example is too compliated for me to understand without great effort, 
perhaps someone else has the time to follow it more closely - it appears to be 
creating and closing many new sessions and add()ing objects between them - an 
unusual series of events.   The policy of add() is that it puts an object in 
the session.  If its already there, nothing happens.   It doesnt invalidate any 
state or reconcile with what's currently visible in the transaction, so if the 
example is attempting to illustrate, transaction A changed a row, but 
transaction B doesn't see it!, you'd have to expire the appropriate parts of 
session B for those changes to be seen.


 
 
 $ cat listdelete.py; python listdelete.py
 
 import sqlalchemy as sql
 from sqlalchemy import orm
 from sqlalchemy.ext.declarative import declarative_base
 
 echo = 0
 engine = sql.create_engine(sqlite:///:memory:, echo=bool(echo))
 metadata = sql.MetaData(bind=engine)
 DB = orm.sessionmaker(bind=engine)
 T = declarative_base(metadata=metadata)
 
 class A(T):
__tablename__ = 'a'
id = sql.Column(sql.Integer, primary_key=True)
info = sql.Column(sql.String)
cc = orm.relation('C',
  backref='a',
  cascade='all,delete-orphan')
def __repr__(self):
return   a: %s cc=%s % (self.info, len(self.cc))
 
 class C(T):
__tablename__ = 'c'
a_id = sql.Column(sql.Integer, sql.ForeignKey('a.id'),
 primary_key=True)
i = sql.Column(sql.Integer, primary_key=True)
 
 def get():
return DB().query(A).first()
 
 def change(a, s, i):
orm.object_session(a).close()
db = DB()
db.add(a)
a.info = s
del a.cc[-1]
a.cc.append(C(i=i))
db.close()
 
 metadata.create_all()
 A.__table__.delete().execute()
 
 db = DB()
 a = A(id=1, info='blah', cc=[C(i=1), C(i=2)])
 db.add(a)
 db.commit()
 db.close()
 
 print get()
 
 # merge and flush
 a = get()
 change(a, 'change one', 3)
 db = DB()
 db.merge(a)
 db.commit()
 db.close()
 
 print get()
 
 # add and flush
 a = get()
 change(a, 'change two', 4)
 db = DB()
 db.add(a)
 db.commit()
 db.close()
 
 print get()
 
 
 a: blah cc=2
 a: change one cc=2
 a: change two cc=3
 
 -- 
 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.



Re: [sqlalchemy] session.add() vs session.merge() and delete child

2010-01-30 Thread Michael Bayer

On Jan 30, 2010, at 9:07 AM, avdd wrote:

 I'm using session.add() to refresh my objects while working on them,
 because I don't want to merge them with the persistent state.  But it
 appears deletes aren't carrying across to child relations:

in r6711 the save-update cascade operation will cascade related objects present 
in the full history of a scalar- or collection- holding relation() attribute 
into the new session, thus allowing objects marked as deleted or disassociated 
from the parent to be present in the new session where they will particpate in 
the next flush().





 
 
 $ cat listdelete.py; python listdelete.py
 
 import sqlalchemy as sql
 from sqlalchemy import orm
 from sqlalchemy.ext.declarative import declarative_base
 
 echo = 0
 engine = sql.create_engine(sqlite:///:memory:, echo=bool(echo))
 metadata = sql.MetaData(bind=engine)
 DB = orm.sessionmaker(bind=engine)
 T = declarative_base(metadata=metadata)
 
 class A(T):
__tablename__ = 'a'
id = sql.Column(sql.Integer, primary_key=True)
info = sql.Column(sql.String)
cc = orm.relation('C',
  backref='a',
  cascade='all,delete-orphan')
def __repr__(self):
return   a: %s cc=%s % (self.info, len(self.cc))
 
 class C(T):
__tablename__ = 'c'
a_id = sql.Column(sql.Integer, sql.ForeignKey('a.id'),
 primary_key=True)
i = sql.Column(sql.Integer, primary_key=True)
 
 def get():
return DB().query(A).first()
 
 def change(a, s, i):
orm.object_session(a).close()
db = DB()
db.add(a)
a.info = s
del a.cc[-1]
a.cc.append(C(i=i))
db.close()
 
 metadata.create_all()
 A.__table__.delete().execute()
 
 db = DB()
 a = A(id=1, info='blah', cc=[C(i=1), C(i=2)])
 db.add(a)
 db.commit()
 db.close()
 
 print get()
 
 # merge and flush
 a = get()
 change(a, 'change one', 3)
 db = DB()
 db.merge(a)
 db.commit()
 db.close()
 
 print get()
 
 # add and flush
 a = get()
 change(a, 'change two', 4)
 db = DB()
 db.add(a)
 db.commit()
 db.close()
 
 print get()
 
 
 a: blah cc=2
 a: change one cc=2
 a: change two cc=3
 
 -- 
 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.