Database 避免三个表之间的循环依赖关系
我正在设计一个数据库来存放科学测试数据,使用sqlalchemy。我遇到了一个我似乎无法解决的问题 在我的测试数据中,每个Database 避免三个表之间的循环依赖关系,database,orm,sqlalchemy,Database,Orm,Sqlalchemy,我正在设计一个数据库来存放科学测试数据,使用sqlalchemy。我遇到了一个我似乎无法解决的问题 在我的测试数据中,每个观测值都有一个状态(位置、速度、加速度),而状态有一个相关的时间(状态应用的时间)。到目前为止,一切顺利。我为时间制作了一个单独的表,因为我处理不同类型的时间,我想使用一个参考表来指示每次的时间类型(状态时间、观察时间等)。我处理的时间类型可能会改变,所以我认为通过这种方式进行规范化,将来可以添加新的时间类型,因为它们只是引用表中的行 到目前为止,这部分工作正常(使用声明式样
观测值
都有一个状态
(位置、速度、加速度),而状态
有一个相关的时间
(状态应用的时间)。到目前为止,一切顺利。我为时间
制作了一个单独的表,因为我处理不同类型的时间,我想使用一个参考表来指示每次的时间类型(状态时间、观察时间等)。我处理的时间类型可能会改变,所以我认为通过这种方式进行规范化,将来可以添加新的时间类型,因为它们只是引用表中的行
到目前为止,这部分工作正常(使用声明式样式):
问题在于观察本身可能有不同的时间。当我尝试在观察
和时间
之间创建一对多关系时,我得到一个循环依赖性错误:
class Observation(Base):
__tablename__ = 'tbl_observations'
id = Column(Integer, primary_key=True)
state_id = Column(Integer, ForeignKey('tbl_states.id'))
state = relationship('State', uselist=False)
# Added this line:
times = relationship('Time')
class Time(Base):
__tablename__ = 'tbl_times'
id = Column(Integer, primary_key=True)
time_type_id = Column(Integer, ForeignKey('ref_tbl_time_types.id'))
time_type = relationship('TimeType', uselist=False)
time_value = Column(Float)
# Added this line:
observation_id = Column(Integer, ForeignKey('tbl_observations.id'))
我猜这是因为原始的观察
->状态
->时间
链有一个指向观察
的引用
有办法解决这个问题吗?我的设计都搞砸了吗?我在炼金术方面做错什么了吗?我对这一切都不熟悉,所以可能是上述任何一种。如果您能提供任何帮助,我们将不胜感激
顺便说一句,我试着按照这里的建议去做:要么我做错了,要么它没有解决我的特殊问题。观察值和状态之间有一种多对一的关系。所以一个状态可以有很多观测,每个观测都有一个状态 状态和时间之间也存在多对一关系。所以一个时间可以有很多状态,每个状态都有一个时间 你是对的,问题是引用了《泰晤士报》的观察结果。你强迫每一次都有一个观察,而这个观察又必须有一个状态,这个状态又必须有一个时间(然后循环永远重复) 要打破这一点,你需要弄清楚你在这些关系中到底想要描绘什么。如果观察有一个状态,它有一个时间,那么观察有一个时间(您可以从该状态获取时间)
所以你需要回答的真正问题是:说一个时间有一个观测值意味着什么?您将如何在应用程序中使用它?观察值和状态之间存在多对一关系。所以一个状态可以有很多观测,每个观测都有一个状态 状态和时间之间也存在多对一关系。所以一个时间可以有很多状态,每个状态都有一个时间 你是对的,问题是引用了《泰晤士报》的观察结果。你强迫每一次都有一个观察,而这个观察又必须有一个状态,这个状态又必须有一个时间(然后循环永远重复) 要打破这一点,你需要弄清楚你在这些关系中到底想要描绘什么。如果观察有一个状态,它有一个时间,那么观察有一个时间(您可以从该状态获取时间)
所以你需要回答的真正问题是:说一个时间有一个观测值意味着什么?您将如何在应用程序中使用它?我想我没有完全了解对象模型中的模型名称以及它们与现实世界的对应关系。但我会试着猜。首先,我怀疑模型
Time
(看起来相当基本,几乎没有逻辑)是否应该有一个ForeignKey
到某个更高级别的模型类观察。有鉴于此,我认为您的模型不是一系列的n-1
关系,而是一种关系。所以我可以看到你的模型如下:
class Base(object):
id = Column(Integer, primary_key=True)
class Observation(Base):
__tablename__ = 'tbl_observations'
class ObservationInstance(Base):
__tablename__ = 'tbl_observation_instances'
observation_id = Column(Integer, ForeignKey('tbl_observations.id'))
state_id = Column(Integer, ForeignKey('tbl_states.id'))
time_id = Column(Integer, ForeignKey('tbl_times.id'))
# relationships
observation = relationship('Observation', backref="instances")
state = relationship('State')
time = relationship('Time')
class State(Base):
__tablename__ = 'tbl_states'
class Time(Base):
__tablename__ = 'tbl_times'
time_type_id = Column(Integer, ForeignKey('ref_tbl_time_types.id'))
time_type = relationship('TimeType', uselist=False)
time_value = Column(Float)
class TimeType(Base):
__tablename__ = 'ref_tbl_time_types'
desc = Column(String)
希望这是有意义的,并且适合您尝试建模的真实世界。我假设你的模型代表某种(科学)实验。在这种情况下,我将重命名Observation->experiment
和observationstance->Observation
我想我没有完全获得对象模型中的模型名称以及它们与现实世界的对应关系。但我会试着猜。首先,我怀疑模型Time
(看起来相当基本,几乎没有逻辑)是否应该有一个ForeignKey
到某个更高级别的模型类观察。有鉴于此,我认为您的模型不是一系列的n-1
关系,而是一种关系。所以我可以看到你的模型如下:
class Base(object):
id = Column(Integer, primary_key=True)
class Observation(Base):
__tablename__ = 'tbl_observations'
class ObservationInstance(Base):
__tablename__ = 'tbl_observation_instances'
observation_id = Column(Integer, ForeignKey('tbl_observations.id'))
state_id = Column(Integer, ForeignKey('tbl_states.id'))
time_id = Column(Integer, ForeignKey('tbl_times.id'))
# relationships
observation = relationship('Observation', backref="instances")
state = relationship('State')
time = relationship('Time')
class State(Base):
__tablename__ = 'tbl_states'
class Time(Base):
__tablename__ = 'tbl_times'
time_type_id = Column(Integer, ForeignKey('ref_tbl_time_types.id'))
time_type = relationship('TimeType', uselist=False)
time_value = Column(Float)
class TimeType(Base):
__tablename__ = 'ref_tbl_time_types'
desc = Column(String)
希望这是有意义的,并且适合您尝试建模的真实世界。我假设你的模型代表某种(科学)实验。在这种情况下,我将重命名<代码>观察> >体验< /代码>和<代码>观察实例>观察< /代码> < p>这里关于重新使用用例的其他答案是有价值的,并且您应该考虑这些。但是,就SQLAlchemy而言,由于多个FK而导致的循环依赖性问题可以通过use\u alter/post\u update组合解决,记录在。以下是使用该模型的模型:
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
Base= declarative_base()
class Observation(Base):
__tablename__ = 'tbl_observations'
id = Column(Integer, primary_key=True)
state_id = Column(Integer, ForeignKey('tbl_states.id'))
state = relationship('State', uselist=False)
times = relationship('Time')
class State(Base):
__tablename__ = 'tbl_states'
id = Column(Integer, primary_key=True)
time_id = Column(Integer, ForeignKey('tbl_times.id'))
# post_update is preferable on the many-to-one
# only to reduce the number of UPDATE statements
# versus it being on a one-to-many.
# It can be on Observation.times just as easily.
time = relationship('Time', post_update=True)
class Time(Base):
__tablename__ = 'tbl_times'
id = Column(Integer, primary_key=True)
time_type_id = Column(Integer, ForeignKey('ref_tbl_time_types.id'))
time_type = relationship('TimeType', uselist=False)
time_value = Column(Float)
observation_id = Column(Integer, ForeignKey('tbl_observations.id',
use_alter=True, name="fk_time_obs_id"))
class TimeType(Base):
__tablename__ = 'ref_tbl_time_types'
id = Column(Integer, primary_key=True)
desc = Column(String)
e = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
Base.metadata.drop_all(e)
Base.metadata.create_all(e)
s = Session(e)
tt1 = TimeType(desc="some time type")
t1, t2, t3, t4, t5 = Time(time_type=tt1, time_value=40), \
Time(time_type=tt1, time_value=50), \
Time(time_type=tt1, time_value=60),\
Time(time_type=tt1, time_value=70),\
Time(time_type=tt1, time_value=80)
s.add_all([
Observation(state=State(time=t1), times=[t1, t2]),
Observation(state=State(time=t2), times=[t1, t3, t4]),
Observation(state=State(time=t2), times=[t2, t3, t4, t5]),
])
s.commit()
在这里,关于重新使用你的用例的其他答案是有价值的,你应该考虑这些。但是,就SQLAlchemy而言,由于多个FK而导致的循环依赖性问题可以通过use\u alter/post\u update组合解决,记录在。以下是使用该模型的模型:
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
Base= declarative_base()
class Observation(Base):
__tablename__ = 'tbl_observations'
id = Column(Integer, primary_key=True)
state_id = Column(Integer, ForeignKey('tbl_states.id'))
state = relationship('State', uselist=False)
times = relationship('Time')
class State(Base):
__tablename__ = 'tbl_states'
id = Column(Integer, primary_key=True)
time_id = Column(Integer, ForeignKey('tbl_times.id'))
# post_update is preferable on the many-to-one
# only to reduce the number of UPDATE statements
# versus it being on a one-to-many.
# It can be on Observation.times just as easily.
time = relationship('Time', post_update=True)
class Time(Base):
__tablename__ = 'tbl_times'
id = Column(Integer, primary_key=True)
time_type_id = Column(Integer, ForeignKey('ref_tbl_time_types.id'))
time_type = relationship('TimeType', uselist=False)
time_value = Column(Float)
observation_id = Column(Integer, ForeignKey('tbl_observations.id',
use_alter=True, name="fk_time_obs_id"))
class TimeType(Base):
__tablename__ = 'ref_tbl_time_types'
id = Column(Integer, primary_key=True)
desc = Column(String)
e = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
Base.metadata.drop_all(e)
Base.metadata.create_all(e)
s = Session(e)
tt1 = TimeType(desc="some time type")
t1, t2, t3, t4, t5 = Time(time_type=tt1, time_value=40), \
Time(time_type=tt1, time_value=50), \
Time(time_type=tt1, time_value=60),\
Time(time_type=tt1, time_value=70),\
Time(time_type=tt1, time_value=80)
s.add_all([
Observation(state=State(time=t1), times=[t1, t2]),
Observation(state=State(time=t2), times=[t1, t3, t4]),
Observation(state=State(time=t2), times=[t2, t3, t4, t5]),
])
s.commit()
谢谢我想要的是观察和状态之间,状态和时间之间的一对一。如果我编错了,请帮帮我。我认为我是如何一对一地做到这一点的。我希望观察值和时间之间是一对多,这意味着观察值有许多不同的时间。@IanVS-这里