对于以下模型,为什么以下交互能够在同一事务期间成功地将重复关联添加到关系中?我预计(并且需要)它会因为将 UniqueConstraint 放置在关联表上而失败。
Models:
from app import db # this is the access to SQLAlchemy
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
sz_shirt_dress_sleeve = db.relationship(
'SizeKeyShirtDressSleeve',
secondary=LinkUserSizeShirtDressSleeve,
backref=db.backref('users', lazy='dynamic'),
order_by="asc(SizeKeyShirtDressSleeve.id)")
class SizeKeyShirtDressSleeve(db.Model):
id = db.Column(db.Integer, primary_key=True)
size = db.Column(db.Integer)
def __repr__(self):
return 'Dress shirt sleeve size: %r' % self.size
LinkUserSizeShirtDressSleeve = db.Table(
'link_user_size_shirt_dress_sleeve',
db.Column(
'size_id',
db.Integer,
db.ForeignKey('size_key_shirt_dress_sleeve.id'), primary_key=True),
db.Column(
'user_id',
db.Integer,
db.ForeignKey('user.id'), primary_key=True),
db.UniqueConstraint('size_id', 'user_id', name='uq_association')
)
由于关联表上的 UniqueConstraint,我预计此交互式会话会导致 IntegrityError。它不允许并且允许我将相同的大小关联两次:
>>> from app.models import User, SizeKeyShirtDressSleeve
>>> db.session.add(User(id=8))
>>> db.session.commit()
>>> u = User.query.filter(User.id==8).one()
>>> u
<User id: 8, email: None, password_hash: None>
>>> u.sz_shirt_dress_sleeve
[]
>>> should_cause_error = SizeKeyShirtDressSleeve.query.first()
>>> should_cause_error
Dress shirt sleeve size: 3000
>>> u.sz_shirt_dress_sleeve.append(should_cause_error)
>>> u.sz_shirt_dress_sleeve.append(should_cause_error)
>>> u.sz_shirt_dress_sleeve
[Dress shirt sleeve size: 3000, Dress shirt sleeve size: 3000]
>>> db.session.commit()
>>>
等等,什么?该关系不代表我的关联表中的内容吗?我想我应该验证一下:
(紧接着,同一会话)
>>> from app.models import LinkUserSizeShirtDressSleeve as Sleeve
>>> db.session.query(Sleeve).filter(Sleeve.c.user_id==8).all()
[(1, 8)]
>>>
So u.sz_shirt_dress_sleeve
wasn't准确地表示关联表的状态。 ...好的。但我需要它。事实上,我确实知道如果我尝试添加另一个就会失败should_cause_error
反对这种关系:
>>> u.sz_shirt_dress_sleeve.append(should_cause_error)
>>> db.session.commit()
# huge stack trace
sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed: link_user_size_shirt_dress_sleeve.size_id, link_user_size_shirt_dress_sleeve.user_id [SQL: 'INSERT INTO link_user_size_shirt_dress_sleeve (size_id, user_id) VALUES (?, ?)'] [parameters: (1, 8)] (Background on this error at: http://sqlalche.me/e/gkpj)
>>>
伟大的!好吧,所以我推断的是:
1) 关系列表中可能存在重复的项目。
2) 关系列表可能无法准确反映其所负责的关联表的状态。
3) 的UniqueConstraint
只要我继续在单独的事务中与关系进行交互(由 session.commit() 打断),就可以工作。
问题:1)、2) 或 3) 是否错误?如何防止我的关系列表中出现重复的项目里面同一个交易?