我在线程之间传递对象ID,并希望能够通过ID将对象合并到会话中。我当然可以跨线程查询对象来实现这一点,但如果对象已经在会话中,则宁愿避免数据库跳转的开销。
我的代码正在运行,但是当我通过父类合并时,它没有正确设置鉴别器值。如何确保正确设置鉴别器?
from sqlalchemy import create_engine, __version__
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column
from sqlalchemy.types import Integer, String
Session = scoped_session(sessionmaker())
Base = declarative_base()
class Person(Base):
__tablename__ = 'person'
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
discriminator = Column(String, nullable=False)
__mapper_args__ = {'polymorphic_identity': 'person',
'polymorphic_on': discriminator}
class Programmer(Person):
__mapper_args__ = {'polymorphic_identity': 'programmer'}
fav_language = Column(String)
engine = create_engine('postgresql+zxjdbc://mnaber:test123@localhost:5432/ajtest2', echo=True)
Session.configure(bind=engine)
Base.metadata.bind = engine
Base.metadata.drop_all(checkfirst=True)
Base.metadata.create_all()
s = Session()
michael = Programmer(name='Michael', fav_language='Python')
s.add(michael)
s.commit()
print "Sqlalchemy Version: %s" % __version__
print "INITIAL: %s %s" % (type(michael), michael.discriminator)
michael_merged = s.merge(Person(id=michael.id)) #Merge by parent class
print "MERGED: %s %s" % (type(michael_merged), michael_merged.discriminator)
print "FINAL: %s %s" % (type(michael), michael.discriminator)
michael_merged.fav_language = 'Jython'
s.add(michael_merged)
s.commit()
有趣的输出是:
Sqlalchemy Version: 0.8.7
INITIAL: <class '__main__.Programmer'> programmer
MERGED: <class '__main__.Programmer'> person
FINAL: <class '__main__.Programmer'> person
site-packages/sqlalchemy/orm/persistence.py:154: SAWarning: Flushing object <Programmer at 0x18> with incompatible polymorphic identity 'person'; the object may not refresh and/or load correctly
mapper._validate_polymorphic_identity(mapper, state, dict_)
我应该如何确保MERGED和FINAL有程序员的鉴别器?
答案 0 :(得分:0)
merge()假设一个对象看起来像你想要的样子,所以你需要在这里传递一个程序员。传入Person(id = 1)当数据库中确实存在该标识的程序员不是受支持的模式时,行为是未定义的。目前发生的事情是你的Person对象在前面设置了“person”的“鉴别器”,因此这是刷新到数据库中的值;它会覆盖会话中已有的内容。
你可以欺骗它像这样工作:
p1 = Person(id=michael.id)
del p1.discriminator
michael_merged = s.merge(p1) #Merge by parent class
但是,我无法保证上述代码将始终适用于未来的SQLAlchemy版本。例如,它不适用于在冲洗时选择“鉴别器”的早期版本。
您的代码示例使得Programmer已经存在于Session中;你可以像这样以类不可知的方式得到这个对象:
obj = session.query(Person).get(michael.id)
然后你有了你的Programmer对象,你可以自由地修改它。