一些背景:
我有一组从基表继承的表,称为things
things
有一个名为objecttypes
的表的外键objecttypes
为每个子表提供polymorphic_identity
值
我发现,当我创建一个新会话时,在某些情况下,旧会话中的数据不会合并到新会话中
如果我有:
eastGate = Gate(name="eastGate", origin=tokyo, destinationInput=luggage, objectType=typeDict['gate'])
其中origin
、destinationInput
和objectType
都是以前定义过对象的关系,我看到以下错误:
sqlalchemy.exc.InvalidRequestError: Can't attach instance <ObjectType at 0x10592fe50>; another instance with key (
<class '__main__.ObjectType'>, (1,), None) is already present in this session.
可能出现这种情况的情况有很多,但在这种特定情况下,情况如下:
# typeDict just contains a pre-fetched ObjectTypes
tokyo = Location(name="tokyo", objectType=typeDict['location'])
tokyo = write(tokyo)
# If I clear out the current session here, the error will occur
scopedSessionFactory().close()
scopedSessionFactory.remove()
westGate = Gate(name="westGate", destination=tokyo, objectType=typeDict['gate'])
westGate = write(westGate)
luggage = LocationInput(name="luggage", objectType=typeDict['locationinput'])
luggage = write(luggage)
# This is the line where the error occurs
eastGate = Gate(name="eastGate", origin=tokyo, destinationInput=luggage, objectType=typeDict['gate'])
eastGate = write(eastGate)
现在我已经重现了这个问题,我不太确定根本原因是什么。在这个特定的例子中,我可以使用相同的会话,但我希望能够缩短一些会话的寿命
环境: Python:2.7.14(也发生在3.7.x上) SqlAlchemy:1.3.20
完整示例如下:
import sqlalchemy as sa
from sqlalchemy import create_engine, inspect, Column, Integer, String, DateTime, ForeignKey
from sqlalchemy.orm import sessionmaker, relationship, aliased, contains_eager, scoped_session
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class ObjectType(Base):
__tablename__ = "objecttypes"
id=Column(Integer, primary_key=True)
name=Column(String)
def __repr__(self):
return "ObjectType({}, id={})".format(self.name, self.id)
engine = create_engine('sqlite:///:memory:', echo=False)
Base.metadata.create_all(engine) # We'll call this again later
sessionFactory = sessionmaker(bind=engine, expire_on_commit=False)
scopedSessionFactory = scoped_session(sessionFactory)
def startScope():
return scopedSessionFactory()
def endScope():
scopedSessionFactory().close()
scopedSessionFactory.remove()
return
def addObjectTypes():
"""
Add in all the object types to the db without using a session
"""
values = ["('location')", "('locationinput')", "('gate')"]
q = """INSERT INTO objecttypes (name) VALUES {}""".format(",".join(values))
engine.execute(q)
return
def buildObjectTypes():
addObjectTypes()
session = startScope()
types = session.query(ObjectType).all()
endScope()
return dict([(objType.name, objType) for objType in types])
# Holds all the types
typeDict = buildObjectTypes()
class Thing(Base):
__tablename__ = "things"
id=Column(Integer, primary_key=True)
name=Column(String)
object_type_id=Column(Integer, ForeignKey('objecttypes.id'))
objectType=relationship(ObjectType)
version=Column(Integer, nullable=False)
timeCreated=Column(DateTime)
__mapper_args__ = {
'version_id_col': version,
'polymorphic_on':object_type_id,
'with_polymorphic':'*',
'polymorphic_load':'inline',
}
def __repr__(self):
return "{}, id={}, type={}, version={}".format(self.name, self.id, self.objectType, self.version)
class Location(Thing):
__tablename__ = "locations"
id=Column(Integer, ForeignKey('things.id'),primary_key=True)
__mapper_args__ = {
'polymorphic_identity': typeDict['location'].id
}
class LocationInput(Thing):
__tablename__ = "locationinputs"
id=Column(Integer, ForeignKey('things.id'),primary_key=True)
previousGateId=Column(Integer, ForeignKey('gates.id'))
__mapper_args__ = {
'polymorphic_identity': typeDict['locationinput'].id
}
class Gate(Thing):
__tablename__ = "gates"
id=Column(Integer, ForeignKey('things.id'),primary_key=True)
originId=Column(Integer, ForeignKey('locations.id'))
origin=relationship(Location, foreign_keys=[originId], backref="originGates")
originInputId=Column(Integer, ForeignKey('locationinputs.id'))
originInput=relationship(LocationInput, foreign_keys=[originInputId], backref="originInputGates")
destinationId=Column(Integer, ForeignKey('locations.id'))
destination=relationship(Location, foreign_keys=[destinationId], backref="destinationGates")
destinationInputId=Column(Integer, ForeignKey('locationinputs.id'))
destinationInput=relationship(LocationInput, foreign_keys=[destinationInputId], backref="destinationInputGates")
__mapper_args__ = {
'polymorphic_identity': typeDict['gate'].id
}
LocationInput.previousGate = relationship(Gate, foreign_keys=[LocationInput.previousGateId])
Base.metadata.create_all(engine)
def write(obj):
session = scopedSessionFactory()
return session.merge(obj)
def reproduceError():
tokyo = Location(name="tokyo", objectType=typeDict['location'])
tokyo = write(tokyo)
# If I clear out the current session here, the error will occur
scopedSessionFactory().close()
scopedSessionFactory.remove()
westGate = Gate(name="westGate", destination=tokyo, objectType=typeDict['gate'])
westGate = write(westGate)
luggage = LocationInput(name="luggage", objectType=typeDict['locationinput'])
luggage = write(luggage)
# This is the line where the error occurs
eastGate = Gate(name="eastGate", origin=tokyo, destinationInput=luggage, objectType=typeDict['gate'])
eastGate = write(eastGate)
print(eastGate)
return
reproduceError()
目前没有回答
相关问题 更多 >
编程相关推荐