SQLАлхимия:Сопоставления объектов потеряны после фиксации?
-
06-07-2019 - |
Вопрос
У меня возникла простая проблема в SQLAlchemy.У меня есть одна модель в таблице, назовем ее здесь Модель1.Я хочу добавить строку в эту таблицу и получить автоинкрементируемый ключ, чтобы я мог создать с ее помощью другую модель и использовать этот ключ.Это не ошибочный дизайн базы данных (отношение 1:1 и т. д.).Мне просто нужен этот ключ в другой таблице, потому что другая таблица передается на удаленный хост, и мне нужны совпадающие ключи, чтобы серверы понимали друг друга.Между этими двумя таблицами больше не будет локальных ссылок, и из-за этого также невозможно создавать связи.
Рассмотрим следующий код:
object1 = model.Model1(param)
DBSession.add(object1)
# if I do this, the line below fails with an UnboundExecutionError.
# and if I dont do this, object1.id won't be set yet
#transaction.commit()
object2 = model.AnotherModel(object1.id) #id holds the primary, autoincremented key
Мне хотелось бы, чтобы мне даже не приходилось совершать коммит «вручную».По сути, я хотел бы добиться того, чтобы «Model1» постоянно росла с увеличением первичного ключа Model.id.AnotherModel — это всегда лишь небольшая часть Model1, которая еще не обработана.Конечно, я мог бы добавить флаг в «Модель1», логическое поле таблицы, чтобы отмечать уже обработанные элементы, но я надеялся, что в этом нет необходимости.
Как я могу заставить мой приведенный выше код работать?
Приветствую,
Том
Решение
Пара вещей:
- Не могли бы вы объяснить, что такое переменная
transaction
связан с? - Какой именно оператор вызывает ошибку UnboundExecutionError?
- Предоставьте полное сообщение об исключении, включая трассировку стека.
- «Нормальным» поступком в этом случае было бы вызвать
DBSession.flush()
.Вы пробовали это?
Пример:
object1 = Model1(param)
DBSession.add(object1)
DBSession.flush()
assert object1.id != None # flushing the session populates the id
object2 = AnotherModel(object1.id)
За отличное объяснение сеанса SA и того, что flush()
делает, см. Использование сеанса.
По сути, flush()
заставляет ожидающие экземпляры становиться постоянными - это означает, что новые объекты вставляются в таблицы базы данных. flush()
также ОБНОВЛЯЕТ таблицы значениями для экземпляров, которые отслеживает сеанс и в которых есть изменения.
commit()
всегда проблемы flush()
первый.
В рамках транзакции вы можете сбрасывать данные несколько раз.Каждый методlush() вызывает UPDATE и/или INSERT в базе данных.Всю транзакцию можно зафиксировать или откатить.
Другие советы
если вы хотите, чтобы новые идентификаторы первичного ключа генерировались без какой-либо фиксации, просто вызовите session.flush().Это отправит все ожидающие в базу данных данные в рамках текущей транзакции.
Я использовал это только с ForeignKeys, поэтому во втором случае вы бы предпочли использовать model.AnotherModel(model1=object1), и тогда это просто сработало (тм).Я подозреваю, что это может быть проблема с вашими моделями, так что, возможно, вы могли бы опубликовать и их?