我有两个班级,Parent
和Child
。父母可以有多个孩子。在我的计划中,我根据需要将孩子贴在父母身上。对于第一个孩子来说,这一直是成功的这是我的关系
class Parent(db.Model):
__tablename__ = 'parent'
id = db.Column(db.Integer, primary_key=True)
children = db.relationship(
'Child',
backref=db.backref('parent', order_by=id)
)
class Child(db.Model):
__tablename__ = 'child'
id = db.Column(db.Integer, primary_key=True)
parent_fk = db.Column(
db.Integer,
db.ForeignKey('parent.id')
)
然后是一次添加一个孩子的代码:
print(parent.children)
parent.children.append(Child())
print(parent.children)
database.update_object(parent) # Uses a scoped session to merge and commit.
这是我的更新代码:
@contextmanager
def session_scope():
try:
yield db.session
db.session.commit()
except Exception as e:
print('Rolling back database')
print(e)
db.session.rollback()
def update_object(obj):
with session_scope() as session:
session.merge(obj)
当我从程序中记录结果时,我得到了这个:
添加第一个孩子:
[]
[<Child None>]
添加第二个孩子:
[<Child 219L>]
[<Child 219L>, <Child None>]
Rolling back database
(OperationalError) (1048, "Column 'parent_fk' cannot be null") 'UPDATE child SET parent_fk=%s WHERE child.id = %s' (None, 218L)
我错过了什么?
FWIW,一致的模式是第二个Child
实例的id
比第一个低{1}。
答案 0 :(得分:2)
错误是由@Override
public void run() {
try {
// Code
} catch (Exception e) {
e.printStackTrace();
}
}
的使用造成的。相反,如果您使用session.merge
,它应该正常工作,因为session.add
执行session.add
操作,我相信您的意图。
此SO answer说明insert-or-update
的使用,我发现它非常有用。链接到它,而不是试图用较差的语言来解释它。
使用代码示例进行编辑,使用session.merge
代替add
时,问题已解决。
merge
如果我理解正确,那就是使用from sqlalchemy import Integer, Column, ForeignKey, create_engine
from sqlalchemy.orm import sessionmaker, relationship, backref
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('postgresql://hal:hal@localhost/hal')
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
children = relationship('Child', backref=backref('parent', order_by=id))
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parent_fk = Column(Integer, ForeignKey('parent.id'))
Base.metadata.create_all(engine)
session_maker = sessionmaker(engine)
s = scoped_session(session)
parent = Parent()
parent.children.append(Child())
s.add(parent)
s.commit()
engine.execute('select * from child').fetchall()
# prints: [(1, 1)]
parent2 = Parent()
s.add(parent2)
s.commit()
parent2.children.append(Child())
parent2.children.append(Child())
parent2.children.append(Child())
# ``parent2`` does not need to be ``added`` to the session again, as
# user this-vidor pointed out in the comments.
# Committing the session will persist the changes, i.e. adding the
# related three child rows to the database.
s.commit()
engine.execute('select * from child').fetchall()
# prints: [(1, 1), (2, 2), (3, 2), (4, 2)]