Как создать непостоянный объект Elixir / SQLAlchemy? - PullRequest
2 голосов
/ 10 мая 2010

Из-за устаревших данных, которые отсутствуют в базе данных, но некоторые внешние файлы, я хочу создать объект SQLAlchemy, который содержит данные, считанные из внешних файлов, но не записывается в базу данных, если я выполняю session.flush()

Мой код выглядит так:

try:
  return session.query(Phone).populate_existing().filter(Phone.mac == ident).one()
except:
  return self.createMockPhoneFromLicenseFile(ident)

def createMockPhoneFromLicenseFile(self, ident):
  # Some code to read necessary data from file deleted....
  phone = Phone()
  phone.mac = foo
  phone.data = bar
  phone.state = "Read from legacy file"
  phone.purchaseOrderPosition = self.getLegacyOrder(ident)
  # SQLAlchemy magic doesn't seem to work here, probably because we don't insert the created
  # phone object into the database. So we set the id fields manually.
  phone.order_id = phone.purchaseOrderPosition.order_id
  phone.order_position_id = phone.purchaseOrderPosition.order_position_id
  return phone 

Все работает нормально, за исключением того, что на session.flush(), выполняемом позже в приложении, SQLAlchemy пытается записать созданный объект Phone в базу данных (что, к счастью, не удается, поскольку phone.state длиннее, чем позволяет тип данных), которая нарушает функцию, которая выдает сброс.

Есть ли способ предотвратить попытки SQLAlchemy написать такой объект?

Обновление

Пока я ничего не нашел на

using_mapper_options(save_on_init=False)

в документации по Elixir (может быть, вы можете предоставить ссылку?), Мне показалось, что стоит попробовать (я бы предпочел способ предотвратить запись одного экземпляра вместо всей сущности).

Сначала казалось, что утверждение не имеет никакого эффекта, и я подозревал, что мои версии SQLAlchemy / Elixir слишком старые, но потом я обнаружил, что соединение с сущностью PurchaseOrderPosition (которое я не изменял) было установлено с

phone.purchaseOrderPosition = self.getLegacyOrder(ident) 

вызывает повторную запись объекта телефона. Если я уберу заявление, все будет в порядке.

Ответы [ 3 ]

3 голосов
/ 10 мая 2010

Вам нужно сделать

import elixir
elixir.options_defaults['mapper_options'] = { 'save_on_init': False }

для предотвращения автоматического добавления * Entity экземпляров, которые вы создаете, в сеанс. В идеале это должно быть сделано как можно раньше в вашем коде. Вы также можете сделать это для каждой отдельной сущности через using_mapper_options(save_on_init=False) - для получения более подробной информации см. Документацию Elixir.

Обновление:

См. этот пост в списке рассылки Elixir, указывающий, что это решение.

Кроме того, как указывает Антс Аасма, вы можете использовать каскадные параметры в отношении Elixir для настройки каскадных параметров в SQLAlchemy. Подробнее см. на этой странице .

0 голосов
/ 11 июля 2012

Старый пост, но я столкнулся с подобной проблемой, в моем случае в sqlalchemy это было вызвано каскадом на backrefs:

http://docs.sqlalchemy.org/en/rel_0_7/orm/session.html#backref-cascade

Отключите его на своих обратных ссылках, чтобы вам пришлось явно добавлять вещи в сессию

0 голосов
/ 10 мая 2010

Ну, по умолчанию sqlalchemy нет.

Рассмотрим следующий автономный пример кода.

from sqlalchemy import Column, Integer, Unicode, create_engine
from sqlalchemy.orm import create_session
from sqlalchemy.ext.declarative import declarative_base

e = create_engine('sqlite://')
Base = declarative_base(bind=e)

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(Unicode(50))

# create the empty table and a session
Base.metadata.create_all()
s = create_session(bind=e, autoflush=False, autocommit=False)

# assert the table is empty
assert s.query(User).all() == []

# create a new User instance but don't save it to database:
u = User()
u.name = 'siebert'
# I could run s.add(u) here but I won't

s.flush()
s.commit()

# assert the table is still empty
assert s.query(User).all() == []

Так что я не уверен, в чём заключается простота добавления ваших экземпляров к сеансу. Обычно вам нужно вручную вызвать s.add(u), чтобы перейти в сеанс. Я не знаком с эликсиром, так что, возможно, это какой-то трюк с эликсиром ... Может быть, вы могли бы удалить его из сеанса, используя session.expunge().

...