【问题标题】:Python/SqlAlchemy 3-way circular dependencyPython/SqlAlchemy 三向循环依赖
【发布时间】:2014-07-02 15:06:31
【问题描述】:

在我的 3 个表之间创建一组关系时遇到问题。当我运行代码来创建表时,我得到一个循环依赖错误。

根据对类似帖子的回复,我尝试摆弄use_alterpost_update,但我无法解决问题。

基本上一张地图有一组位置,一个角色有一组地图,但一个角色也位于其中一个地图位置。 此外,一个地图可以与其他地图有父/子关系。

class Character(Base):
    __tablename__ = 'character'

    ID = Column(Integer, primary_key=True)
    name = Column(Unicode(255), nullable=False)
    classID = Column(Integer, nullable=False)
    created = Column(DateTime, nullable=False, default=datetime.datetime.utcnow)

    profileID = Column(Integer, ForeignKey('profile.ID'), nullable=False)
    locationID = Column(Integer, ForeignKey('location.ID'))

    location = relationship("Location")
    maps = relationship("Map", backref="owner", cascade="save-update, merge, delete, delete-orphan")

class Map(Base):
    __tablename__ = 'map'

    ID = Column(Integer, primary_key=True)
    name = Column(Unicode(255))
    maptypeID = Column(Integer, nullable=False)
    created = Column(DateTime, nullable=False, default=datetime.datetime.utcnow)

    parentID = Column(Integer, ForeignKey('map.ID'))
    ownerID = Column(Integer, ForeignKey('character.ID'))

    children = relationship("Map", backref=backref("parent", remote_side="Map.ID"))
    locations = relationship("Location", backref='map', cascade="save-update, merge, delete, delete-orphan")

class Location(Base):
    __tablename__ = 'location'

    ID = Column(Integer, primary_key=True)
    x = Column(Integer, nullable=False)
    y = Column(Integer, nullable=False)
    locationtypeID = Column(Integer, nullable=False)
    created = Column(DateTime, nullable=False, default=datetime.datetime.utcnow)

    mapID = Column(Integer, ForeignKey('map.ID'), nullable=False)

我该如何解决这个问题?

编辑(已解决):

在使用use_alter 进行了更多尝试之后,我能够通过将 Location 类中的 mapID 定义更改为:

mapID = Column(Integer, ForeignKey('map.ID'), nullable=False)

收件人:

mapID = Column(Integer, ForeignKey('map.ID', use_alter=True, name="fk_location_map"), nullable=False)

为了响应打破循环依赖的建议,我宁愿在架构中表示正确的关系和数据完整性。我宁愿担心修复 ORM 问题或更改 ORM,也不愿捏造架构以符合 ORM 的期望。

在这种特殊情况下,我想不出一种更简洁和优雅的方式来表示我需要模式来表示的所有 信息(在这个词的最基本意义上)为应用程序。

旁注:在与其他语言/框架/ORM 合作后,这种混乱通常由 ORM 自动解决。例如,在 .NET E/F 中,我相信 FK 约束通常是在所有表创建语句之后添加和激活的。

【问题讨论】:

标签: python sqlalchemy circular-dependency


【解决方案1】:

您可能可以使用 alembic 来帮助您解决架构中的循环依赖问题,但我不会帮助您。相反,我将强烈敦促您打破循环依赖

如果我了解您的架构,您的模型中的房间或建筑物由Location 表示。您架构中的玩家/怪物是Characters,在任何时候都必须恰好在一个location 中。此外,还有一些 Map 项目在四处飘荡,它们总是大约一些特定的 location,并且总是恰好在一个 character 的库存中。

这就是我的拼写方式

class Location:
    id = Column(Integer, primary_key=True)

class Character:
    id = Column(Integer, primary_key=True)
    location_id = Column(ForeignKey(Location.id))

    location = relationship(Location, backref="characters")

class Map:
    id = Column(Integer, primary_key=True)
    location_id = Column(ForeignKey(Location.id))
    owner_id = Column(ForeignKey(Character.id))

    location = relationship(Location, backref="maps")
    owner = relationship(Character, backref="inventory")

【讨论】:

  • 这很接近,但并不完全正确。一个角色只代表一个玩家的角色。地图不是一个项目,它只是一个带有名称的位置集合(以及一些脚本和其他附加的东西)。地图及其位置将在运行时动态生成,因此我希望每个角色拥有一组生成的地图及其位置,这些地图对角色来说是独一无二的。
  • 另一个需要注意的是,一张地图可以是另一张地图的子地图。沿着世界地图 -> 国家地图 -> 城市地图 -> 区域地图的思路思考。因此,世界地图上下文中的位置可以代表国家,而在城市地图上下文中,它们可以代表城市的区域。
  • So er... Character -> Map* -> Location 形成一棵树,Character 位于根部,Location 位于叶部,以及Map 之间的任意长度的非循环路径他们?
  • 它可以被解释为一棵树,但我会犹豫这样做。每张地图都会有位置,但每张地图也可以有父地图和子地图。这些位置可以被认为是与树正交的。它们作为地图的属性存在,但与地图的层次结构无关。一个位置如何连接两个地图的细节可能是另一个映射表(因为会有一些奇怪的情况,例如迷宫和一个位置能够根据某些条件导致不同的地图等)。
猜你喜欢
  • 2011-08-16
  • 1970-01-01
  • 2011-09-18
  • 2010-10-28
  • 1970-01-01
  • 1970-01-01
  • 2013-02-19
  • 2010-09-12
相关资源
最近更新 更多