2

由于遗留数据在数据库中不可用,但有一些外部文件,我想创建一个 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) 

导致电话对象再次被写入。如果我删除该声明,一切似乎都很好。

4

3 回答 3

3

你需要做

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

以防止Entity您实例化的实例自动添加到会话中。理想情况下,这应该尽早在您的代码中完成。using_mapper_options(save_on_init=False)您也可以通过- 查看 Elixir 文档了解更多详细信息,基于每个实体执行此操作。

更新:

请参阅Elixir 邮件列表上的这篇文章,表明这是解决方案。

此外,正如 Ants Aasma 指出的那样,您可以在 Elixir 关系上使用级联选项来设置 SQLAlchemy 中的级联选项。有关详细信息,请参阅此页面。

于 2010-05-10T17:45:07.227 回答
0

好吧,默认情况下 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()

于 2010-05-10T17:34:56.590 回答
0

旧帖子,但我遇到了类似的问题,在我的 sqlalchemy 中,它是由反向引用的级联引起的:

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

在你的 backrefs 上关闭它,这样你就必须明确地将东西添加到会话中

于 2012-07-11T13:12:35.380 回答