Python 在向会话添加同一实体两次时,如何防止IntegrityError?
下面的(可执行)代码会导致Python 在向会话添加同一实体两次时,如何防止IntegrityError?,python,sqlalchemy,Python,Sqlalchemy,下面的(可执行)代码会导致IntegrityError,因为具有相同PK的实体会两次(隐式)添加到会话中。会话不知道实体代表相同的对象(相同的主键),并触发两条INSERT语句。我的印象是,会话应该自动检测到这一点。我意识到这两个实体都是暂时的/分离的,我需要执行合并,以获得托管实例。但这不是可以避免的吗 关于示例代码的一些注释: 为了演示手头的问题,它被大大简化了。我拥有的真正代码要复杂得多 需要注意的一点是,主实体是使用函数“build_data”构建的,该函数没有任何会话引用。会话是在应
IntegrityError
,因为具有相同PK的实体会两次(隐式)添加到会话中。会话不知道实体代表相同的对象(相同的主键),并触发两条INSERT
语句。我的印象是,会话应该自动检测到这一点。我意识到这两个实体都是暂时的/分离的,我需要执行合并
,以获得托管实例。但这不是可以避免的吗
关于示例代码的一些注释:
- 为了演示手头的问题,它被大大简化了。我拥有的真正代码要复杂得多
- 需要注意的一点是,主实体是使用函数“build_data”构建的,该函数没有任何会话引用。会话是在应用程序的更高级别上创建的
和User
的概念仅用于说明。实际上,这是不同的商业实体。我在这里用“文章”和“用户”取代了它们,因为这是一个众所周知的概念Article
- 在创建
和article
之间,发生了许多其他事情,创建了一个相当复杂的数据结构。我也不知道哪一行首先发生,因为涉及到非确定性循环(通过字典键)article2
- 将会话传递给
功能,并根据需要进行生成数据
,或合并
- 保留对实例的手动引用,并且只创建一次
from sqlalchemy import (
create_engine,
Column,
ForeignKeyConstraint,
Unicode,
)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import (
relationship,
sessionmaker)
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
name = Column(Unicode, nullable=False, primary_key=True)
class Article(Base):
__tablename__ = 'article'
__table_args__ = (
ForeignKeyConstraint(
['user_'],
['user.name'],
ondelete='CASCADE',
onupdate='CASCADE'),
)
user_ = Column(Unicode, nullable=False, primary_key=True,
)
title = Column(Unicode, nullable=False, primary_key=True)
content = Column(Unicode)
user = relationship(User, backref='articles')
# Prepare the session
Session = sessionmaker()
engine = create_engine('sqlite:///:memory:', echo=True)
Session.configure(bind=engine)
Base.metadata.create_all(engine)
# --- The main code -----------------------------------------------------------
def build_data():
user = User(name='JDoe')
article = Article(user=user, title='Hello World', content='Foobar')
print(article)
# More stuff is happening here.
article2 = Article(user=user, title='Hello World', content='Foobar')
print(article2)
return user
session = Session()
entity = build_data()
session.add(entity)
session.flush()
# -----------------------------------------------------------------------------