【问题标题】:How to use Propel class delegation如何使用 Propel 类委托
【发布时间】:2013-06-23 14:58:21
【问题描述】:

我正在使用 Propel 1.7-dev 并且正在玩 class delegation 即表“继承”。我已经将 Propel1 和 Phing 设置为 Git 子模块,并且每个都在各自的主模块上检出。我的模型建立起来,我可以让层次结构工作,但如果我按照文档(可以说更干净)来做,那么它就会失败。

这是我的模型的相关 sn-p:

<table name="process_step">
    <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" />
    <column name="process_id" type="integer" required="true" />
    <column name="ordinal" type="integer" required="true" />
    <column name="comment" type="varchar" size="256" />
    <column name="type" type="enum" required="true"
        valueSet="load, submit_form, check_page, get_links"
    />
    <column name="is_enabled" type="boolean" required="true" default="false" />

    <foreign-key foreignTable="process">
        <reference local="process_id" foreign="id" />
    </foreign-key>
</table>

<table name="process_step_load">
    <column name="id" type="integer" required="true" primaryKey="true" />
    <behavior name="delegate">
        <parameter name="to" value="process_step" />
    </behavior>
    <column name="url" type="varchar" size="1024" />
    <column name="method" type="varchar" size="6" required="true" default="get" />
</table>

实际上还有更多的子模型,但为了简洁起见,我将它们删除了。

首先要注意的是文档显示父类和子类定义都具有自动递增的主键。但是这是不可能的:主键必须在父项中设置,并复制到子项中(因为父项总是有一行)。我认为这是文档中的一个错误,但我会在这个问题之后提供一个补丁,以防我误解了什么。

所以,这是我的工作代码:

    $process = new Process();

    $processStep = new ProcessStep();
    $processStep->setOrdinal(1); // Simplified for brevitiy
    $processStep->setType(1); // Ditto
    $processStep->setProcess($process);

    // This creates a primary key which we use below (i.e. a cascading
    // save won't work)
    $processStep->save();

    $processStepChild->setId($processStep->getId());
    $processStepChild->save();

文档是这样的:

    $process = new Process();

    $processStep = new ProcessStep();
    $processStep->setOrdinal(1); // Simplified for brevitiy
    $processStep->setType(1); // Ditto
    $processStep->setProcess($process);

    $processStepChild->setProcessStep($processStep);
    $processStepChild->save();

这样做的结果是,在我创建四个子行(每个不同类型)的地方,主键在父级(ProcessStep)中设置得很好,但在子级(ProcessStepLoad 和其他)中都设置为零.

即使我添加了中间保存,这也无济于事。因此,在我看来,$processStepChild-&gt;setProcessStep($processStep) 是问题所在 - 它应该在委托子节点上,并将该子节点的主键更改为提供的父节点的键。它显然没有这样做。

一些可能相关的问题:

  • 我是否正确理解了类委派?据我所知,父键应该是自动递增的主键,并且必须在子键中用作手动主键以形成层次关系。 (旁白:我原以为有一种方法可以自动确定父级的类型,但鉴于它本身不添加类型列,这是不可能的。这就是我在其中添加enum 的原因父母手动)
  • 我使用 Propel master 而不是 1.6.x 正式版本会破坏某些东西吗?

【问题讨论】:

    标签: php mysql propel


    【解决方案1】:

    对,我刚刚切换到 MySQL 的 InnoDB 引擎,所以我可以利用约束,我的新父表如下所示。这说明了哪里出了问题;表格上的关系是错误的:

    CREATE TABLE `process_step`
    (
        `id` INTEGER NOT NULL AUTO_INCREMENT,
        `process_id` INTEGER NOT NULL,
        `ordinal` INTEGER NOT NULL,
        `comment` VARCHAR(256),
        `type` TINYINT NOT NULL,
        `is_enabled` TINYINT(1) DEFAULT 0 NOT NULL,
        PRIMARY KEY (`id`),
        INDEX `process_step_FI_1` (`process_id`),
        CONSTRAINT `process_step_FK_1`
            FOREIGN KEY (`process_id`)
            REFERENCES `process` (`id`),
        CONSTRAINT `process_step_FK_2`
            FOREIGN KEY (`id`)
            REFERENCES `process_step_load` (`id`)
            ON DELETE CASCADE,
        CONSTRAINT `process_step_FK_3`
            FOREIGN KEY (`id`)
            REFERENCES `process_step_submit_form` (`id`)
            ON DELETE CASCADE,
        CONSTRAINT `process_step_FK_4`
            FOREIGN KEY (`id`)
            REFERENCES `process_step_check_page` (`id`)
            ON DELETE CASCADE,
        CONSTRAINT `process_step_FK_5`
            FOREIGN KEY (`id`)
            REFERENCES `process_step_get_links` (`id`)
            ON DELETE CASCADE
    ) ENGINE=InnoDB;
    

    最后四个(子表)当然是错误的:我们不能对每个子表都有一个外键,因为这需要每个子表扩展每个父表。事实证明,这发生在孩子没有明确的 FK 的情况下。因此,我更改了架构中的子类以将 FK 包含到父类中:

    <table name="process_step_load">
        <column name="id" type="integer" required="true" primaryKey="true" />
        <foreign-key foreignTable="process_step">
            <reference local="id" foreign="id" />
        </foreign-key>
        <behavior name="delegate">
            <parameter name="to" value="process_step" />
        </behavior>
        <column name="url" type="varchar" size="1024" />
        <column name="method" type="varchar" size="6" required="true" default="get" />
    </table>
    

    这会在数据库中正确创建约束:

    DROP TABLE IF EXISTS `process_step`;
    
    CREATE TABLE `process_step`
    (
        `id` INTEGER NOT NULL AUTO_INCREMENT,
        `process_id` INTEGER NOT NULL,
        `ordinal` INTEGER NOT NULL,
        `comment` VARCHAR(256),
        `type` TINYINT NOT NULL,
        `is_enabled` TINYINT(1) DEFAULT 0 NOT NULL,
        PRIMARY KEY (`id`),
        INDEX `process_step_FI_1` (`process_id`),
        CONSTRAINT `process_step_FK_1`
            FOREIGN KEY (`process_id`)
            REFERENCES `process` (`id`)
    ) ENGINE=InnoDB;
    
    -- ---------------------------------------------------------------------
    -- process_step_load
    -- ---------------------------------------------------------------------
    
    DROP TABLE IF EXISTS `process_step_load`;
    
    CREATE TABLE `process_step_load`
    (
        `id` INTEGER NOT NULL,
        `url` VARCHAR(1024),
        `method` VARCHAR(6) DEFAULT 'get' NOT NULL,
        PRIMARY KEY (`id`),
        CONSTRAINT `process_step_load_FK_1`
            FOREIGN KEY (`id`)
            REFERENCES `process_step` (`id`)
    ) ENGINE=InnoDB;
    

    这允许我按照文档使用级联保存,耶!

    故事的寓意:(a) 我应该更仔细地阅读文档,(b) 文档完美正确地说明了许多:1 继承,(c) 设置了我的外键,1:1 继承也可以在推进。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-26
      • 1970-01-01
      • 2015-11-18
      • 2018-10-27
      • 1970-01-01
      • 1970-01-01
      • 2019-10-07
      • 2012-02-13
      相关资源
      最近更新 更多