SQLAlchemy está diseñado para tener un solo objeto con cada identidad en sesión. Pero a veces tiene que volver a crear un objeto con identidad conocida, p. cuando lo obtiene de la red o cuando implementa el bloqueo sin conexión para evitar transacciones largas. Y cuando crea un objeto con identidad conocida que pueda existir en la base de datos, existe la posibilidad de que la sesión ya rastree un objeto con esta identidad. Para eso sirve el método merge()
: devuelve un objeto adjunto a la sesión, evitando así objetos duplicados con la misma identidad en la sesión. A continuación se muestra un ejemplo que ilustra lo que está pasando:
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
La salida es:
True False
value2
Así session.merge(obj2)
descubre que hay un objeto con la misma identidad (obj1
creado anteriormente), por lo que se funde la estado de obj2
en un objeto existente y lo devuelve.
A continuación se muestra otro ejemplo, que ilustran la carga de estado de la base de datos:
# ...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
La salida es:
False False
value1-2 value2-1
Ahora merge()
No ha encontrado el objeto con la misma identidad en la sesión, desde que lo borramos. También creé un nuevo objeto con estado parcialmente asignado, pero el resto se carga desde la base de datos.
Gracias por una buena explicación, tenía algunas sombras sobre la idea detrás de _merge() _, ahora lo entiendo – Humoyun