SQLAlchemy разработан, чтобы иметь один объект с каждым идентификатором в сеансе. Но иногда вам нужно воссоздать объект с известной идентичностью, например, когда вы получаете его из сети или когда вы используете автономную блокировку, чтобы избежать длительных транзакций. И когда вы создаете объект с известным идентификатором, который может существовать в базе данных, существует вероятность того, что сеанс уже отслеживает объект с этим идентификатором. Вот для чего нужен метод merge()
: он возвращает объект, присоединенный к сеансу, тем самым избегая дублирования объектов с одинаковым идентификатором в сеансе. Ниже приведен пример, иллюстрирующий происходящее:
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
Вывод:
True False
value2
Таким образом, session.merge(obj2)
обнаруживает, что существует объект с такой же идентичностью (obj1
, созданный выше), поэтому он сливает состояние obj2
в существующий объект и возвращает его.
Ниже приведен еще один пример, иллюстрирующий состояние загрузки из базы данных:
# ...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
Вывод:
False False
value1-2 value2-1
Теперь merge()
не нашел объект с таким же идентификатором в сеансе, так как мы удалили его. Также я создал новый объект с частично присвоенным состоянием, но остальное загружается из базы данных.