English 中文(简体)
Can SQLAlchemy s session.merge() update its result with newer data from the database?
原标题:

The SQLAlchemy documentation says "session.merge() reconciles the current state of an instance and its associated children with existing data in the database".

Does the existing object s state ever get updated by newer data from the database? How? When?

最佳回答

SQLAlchemy is designed to have single object with each identity in session. But sometimes you have to recreate an object with known identity, e.g. when you get it from network or when you implement offline lock to avoid long transactions. And when you create an object with known identity that might exist in database, there is a chance that session already track an object with this identity. That s what merge() method is for: it returns an object attached to the session, thus avoiding duplicate objects with the same identity in the session. Below is an example illustrating what is going on:

from sqlalchemy import *
from sqlalchemy.orm import *

metadata = MetaData()

t = Table(
     t , metadata,
    Column( id , Integer, primary_key=True),
    Column( state , String(10)),
)

class Model(object): pass

mapper(Model, t)

engine = create_engine( sqlite:// )
metadata.create_all(engine)

session = sessionmaker(bind=engine)()

obj1 = Model()
obj1.state =  value1 
session.add(obj1)
session.commit()
obj_id = obj1.id

obj2 = Model()
obj2.id = obj_id
obj2.state =  value2 
obj3 = session.merge(obj2)
session.commit()
print obj3 is obj1, obj3 is obj2
print obj3.state

The output is:

True False
value2

Thus session.merge(obj2) discovers that there is an object with the same identity (obj1 created above), so it merges the state of obj2 into existing object and returns it.

Below is another example, which illustrate loading state from database:

# ...skipped...

t = Table(
     t , metadata,
    Column( id , Integer, primary_key=True),
    Column( state1 , String(10)),
    Column( state2 , String(10)),
)

# ...skipped...

obj1 = Model()
obj1.state1 =  value1-1 
obj1.state2 =  value2-1 
session.add(obj1)
session.commit()
obj_id = obj1.id
session.expunge_all()

obj2 = Model()
obj2.id = obj_id
obj2.state1 =  value1-2 
obj3 = session.merge(obj2)
session.commit()
print obj3 is obj1, obj3 is obj2
print obj3.state1, obj3.state2

The output is:

False False
value1-2 value2-1

Now merge() didn t find the object with the same identity in the session, since we expunged it. Also I created new object with state partially assigned, but the rest is loaded from database.

问题回答

One thing I noticed about merge is that even accessing a field on the unattached object will cause it to be modified during a merge.

For example, if I have a simple class

class X(Base):
    __tablename__=  x 

    id = Column(Integer, primary_key=True)
    name = Column(String)
    value = Column(String)

and a row

(1,  foo ,  bar )

then the following seems to merge nicely:

x = X(id=1)
merged_x = session.merge(x)

print merged_x.name         #  foo 
print merged_x.description  #  bar 

But if I even read name or description, this happens

x = X(id=1)
print x.name                # None

merged_x = session.merge(x)

print merged_x.name         # None
print merged_x.description  #  bar 

This is counterintuitive and, I d argue, incorrect. Is there a way to turn off this behavior? Apparently the mere presence of an attribute in __dict__ causes this to happen. This feature should be noted in the documentation.





相关问题
Can Django models use MySQL functions?

Is there a way to force Django models to pass a field to a MySQL function every time the model data is read or loaded? To clarify what I mean in SQL, I want the Django model to produce something like ...

An enterprise scheduler for python (like quartz)

I am looking for an enterprise tasks scheduler for python, like quartz is for Java. Requirements: Persistent: if the process restarts or the machine restarts, then all the jobs must stay there and ...

How to remove unique, then duplicate dictionaries in a list?

Given the following list that contains some duplicate and some unique dictionaries, what is the best method to remove unique dictionaries first, then reduce the duplicate dictionaries to single ...

What is suggested seed value to use with random.seed()?

Simple enough question: I m using python random module to generate random integers. I want to know what is the suggested value to use with the random.seed() function? Currently I am letting this ...

How can I make the PyDev editor selectively ignore errors?

I m using PyDev under Eclipse to write some Jython code. I ve got numerous instances where I need to do something like this: import com.work.project.component.client.Interface.ISubInterface as ...

How do I profile `paster serve` s startup time?

Python s paster serve app.ini is taking longer than I would like to be ready for the first request. I know how to profile requests with middleware, but how do I profile the initialization time? I ...

Pragmatically adding give-aways/freebies to an online store

Our business currently has an online store and recently we ve been offering free specials to our customers. Right now, we simply display the special and give the buyer a notice stating we will add the ...

Converting Dictionary to List? [duplicate]

I m trying to convert a Python dictionary into a Python list, in order to perform some calculations. #My dictionary dict = {} dict[ Capital ]="London" dict[ Food ]="Fish&Chips" dict[ 2012 ]="...

热门标签