SqlAlchemy - 经典映射继承 - 实例具有空标识(identity)

4
当我尝试将映射到继承另一个表的对象写出时,出现了NULL身份键错误。我发现在使用声明性方法时,此示例可以正常工作,但在使用传统方法时无法正常工作。
表格设置如下:
objecttypes = Table('objecttypes', metadata,
                    Column('id', Integer, primary_key=True),
                    Column('name', String)
                    )
things = Table('things', metadata,
               Column('id', Integer, primary_key=True, autoincrement=True),
               Column('name', String),
               Column('object_type_id', Integer, ForeignKey('objecttypes.id')),
               Column('version', Integer),
               Column('timeCreated', DateTime)
               )
locations = Table('locations', metadata,
                  Column('id', Integer, ForeignKey('things.id'), primary_key=True))

objecttypes = Table('objecttypes', metadata,
                    Column('id', Integer, primary_key=True),
                    Column('name', String)
                    )
mapper(Thing, things, version_id_col=things.c.version,
       polymorphic_on="object_type_id",
       with_polymorphic='*',
       polymorphic_load='inline',
       properties={
           'objectType': relationship(ObjectType, cascade_backrefs=False)
       })
mapper(Location, locations, polymorphic_identity=typeDict['location'].id)

课程设置如下:

class ObjectType(object):
    def __repr__(self):
        return "ObjectType({}, id={})".format(self.name, self.id)

class Thing(object):
    def __init__(self, **kwds):
        for key in kwds:
            setattr(self, key, kwds[key])
        return

    def __repr__(self):
        return "{}, id={}, type={}, version={}".format(self.name, self.id, self.objectType, self.version)

class Location(Thing):
    pass

当我尝试创建和合并新位置时,出现了错误:

def write(obj):
    session = scopedSessionFactory()
    obj = session.merge(obj)
    session.commit()
    return obj

# typeDict is a predefined list ObjectType records
tokyo = Location(name="tokyo", objectType=typeDict['location'])
tokyo = write(tokyo)

错误显示为:
sqlalchemy.orm.exc.FlushError: Instance <Location at 0x10473a950> has a NULL identity key.

完整示例可作为gist使用。


1
似乎 Location 实例中有一些值没有被设置。 - Chandan
1
请将下面的行改为:mapper(Location,locations,inherits=Thing,polymorphic_identity = typeDict ['location'] .id)。我觉得您漏掉了inherits = Thing - fedepad
1个回答

4

我认为问题可能出在SQLA文档中的这些微妙的行中,以下是可能的原因:

https://docs.sqlalchemy.org/en/13/orm/mapping_api.html#sqlalchemy.orm.mapper.params.inherits

我在此报告并加粗关键部分,这些部分可能指向至少部分解决您的问题的方法:
映射类或相应 Mapper 指示该 Mapper 应从中继承的超类。此处映射的类必须是另一个 Mapper 类的子类。当使用 Declarative 时,由于声明类的自然层次结构,此参数会自动传递。
因此,当使用声明性语法时,您不会遇到此问题,因为它会自动传递,但经典方法不会,因此需要指定它。
因此,我认为 Location 的 mapper 行应该是以下内容:
mapper(Location, locations, inherits=Thing, polymorphic_identity=typeDict['location'].id)

你会注意到添加了inherits=Thing

事实上,使用你的代码我也复制了同样的错误,但是进行这个修改之后,我不再遇到那个错误了。我还没有检查代码的其余部分是否正确。


更新: 以下SO帖子展示了没有明确参考SQLA文档的继承类似例子。

SQLAlchemy,使用经典映射实现多态继承

需要SqlAlchemy单表继承的经典映射示例


没错,就是这个。我实际上在发布悬赏几分钟后就找到了它,但我觉得在悬赏结束之前看看有没有人能够找到它更有趣。干得好。 - funseiki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接