0

我有一对 PostgreSQL 表,看起来有点像这样(简化示例):

CREATE TABLE people (
    id SERIAL PRIMARY KEY,
    created timestamp with time zone DEFAULT now() NOT NULL,
    modified timestamp with time zone NULL,
    email varchar NOT NULL UNIQUE,
    inactive boolean NOT NULL DEFAULT False
);

CREATE TABLE engineers (
    id integer NOT NULL REFERENCES people(id) ON DELETE CASCADE ON UPDATE CASCADE UNIQUE,
    created timestamp with time zone DEFAULT now() NOT NULL,
    modified timestamp with time zone NULL,
    login_name varchar NOT NULL UNIQUE,
    PRIMARY KEY(id)
);

engineers继承自,people因为“id”列作为外键people传递。engineers此列也被定义为两个表中的主键。如果我想使用某人的电子邮件地址查询 login_name,可以通过 SQL 像这样完成:

SELECT p.email FROM engineers e 
  JOIN people p ON p.id = e.id 
  WHERE p.inactive = False AND e.login_name = 'john.smith';

如何使用 SQLAlchemy 的声明式样式对这种关系进行建模并执行类似的查询?似乎“ Joined Table Inheritance ”描述了我的使用场景,但我的表中没有鉴别器列。我也一直在尝试使用“ Concrete Table Inheritance ”,但我只是设法让自己感到困惑。

我会很感激任何建议。谢谢!

已编辑

这种表结构之所以如此,是因为“人”可能是“工程师”、“会计师”或“测试员”(或三者的某种组合)。该people表包含每个人共有的属性,例如姓名、电话、号码、雇用日期等。

表上的“created”和“modified”列engineers不共享people;这两列对于每个表都是不同的。这些不是绝对必要的,它们只是默认添加到数据库中的每个表定义中,并用于跟踪更改以进行审计/日志记录。

4

1 回答 1

0

你在这里所拥有的不是任何一种类型,因为你复制了一些列而不是其他列。

文档

SQLAlchemy 支持三种继承形式:单表继承,其中几种类型的类由单个表表示,具体表继承,其中每种类型的类由独立的表表示,以及连接表继承,其中类层次结构被分解在依赖表中,每个类都由其自己的表表示,该表仅包含该类的本地属性。

因为您复制了createdandmodified列,所以这是具体继承的候选对象。但是,因为您希望Employee是一个不包含来自 的列的不完整实体Person,所以这也是连接表继承。

我建议您尝试使其适合连接表继承,但我不完全确定映射器将如何处理重复列的存在。在连接表继承中可以将子类作为关系单独操作,但我不确定它们将如何合并,是否可以合并,或者哪些映射器配置可用于处理使用哪个映射器。如果有办法,本节可能会向您展示如何。

但是,这里有一些东西可以帮助您入门。polymorphic_on也可以是任何 sql 表达式(向下滚动到 polymorphic_on 参数) ——它不必是列。如果您唯一的子类是表,则在鉴别器中engineers使用子查询。EXISTS

下面是一些未经测试的代码,如果不弄乱它,它们可能无法工作——它只是向您展示了您必须使用的模式。

people_table = Table('people', metadata,
    Column('id', Integer, primary_key=True),
    Column('email', String, unique=True),
    Column('inactive', Boolean, default=False),
)

engineers_table = Table('engineers', metadata,
    Column('id', Integer, ForeignKey('people.id'), primary_key=True),
    Column('engineer_info', String),
)

class Person(object):
    pass

class Engineer(Person):
    pass


discriminator = case(
    [
        (exists().where(people_table.c.id==engineers_table.c.id), 'engineer'),
    ], else_='person')

mapper(Person, people_table, polymorphic_identity='person', polymorphic_on=discriminator)
mapper(Engineer, engineer_table, polymorphic_identity='engineer')

不用说,如果可能的话,为了您自己的理智,您应该这样做:

  1. 将鉴别器列添加到您的person表中。
  2. 去掉表格中的createdmodifiedengineer
于 2013-05-06T04:11:36.900 回答