下面的(可执行)代码会导致IntegrityError
,因为具有相同PK的实体会被添加两次(隐式)到会话。会话不知道实体表示相同的对象(相同的PK)并触发两个INSERT
语句。我的印象是会话应该自动检测到。我意识到这两个实体都是瞬态/分离的,我需要执行merge
来获取托管实例。但这是不可避免的吗?
关于示例代码的一些注释:
User
和Article
的概念仅供参考。实际上,它是不同的商业实体。我在这里用“article”和“user”替换它们,因为它是一个众所周知的概念。article
和article2
之间发生了很多其他事情,创建了一个相当复杂的数据结构。我还不知道哪一行首先发生,因为涉及非确定性循环(通过字典键)。我可以通过以下方式解决这个问题:
build_data
功能和merging
,或我想知道的是:我可以避免上述两种方法来保持代码简单吗?
以下是相关代码:
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()
# -----------------------------------------------------------------------------