【问题标题】:Working with models which don't have a single foreign key in CakePHP在 CakePHP 中使用没有单个外键的模型
【发布时间】:2009-10-30 06:23:13
【问题描述】:

我正在开发一个应用程序,该应用程序的数据从外部(并且完全不可更改)源导入。我将简化一些表格来解释问题。下面是带有主键的表。

invoices     (doc_number, date_printed, batch_number)
headers      (doc_number, date_printed, batch_number)
deliveries   (doc_number, date_printed, batch_number)
transactions (doc_number, date_printed, batch_number, line_number)
messages     (doc_number, date_printed, batch_number, line_number)

因此您可以看到发票、抬头和交货具有一对一的关系。发票到交易和发票到消息是一对多的。

在将这些表导入我自己的数据库时,我已将现有主键更改为唯一键,并在每个表上添加了一个 auto_incrementing 字段 (id)。

现在的问题是在 Cake 中设置关系,因为它根本不处理复合键。我已经能够让一对一的关系像这样工作:

class Invoice extends AppModel {
    public $name = "Invoice"
         , $hasOne = array(
            "Header" => array(
                'foreignKey' => false,
                'conditions' => array(
                    "Invoice.doc_number = Header.doc_number",
                    "Invoice.date_printed = Header.date_printed",
                    "Invoice.batch_number = Header.batch_number"
                )
            )
         )
    ;
}

这很有效,因为一对一的关系是通过一个大的 LEFT JOIN 一次性查询的。尝试使用一对多关系(例如,使用 Invoices 和 Transactions)的相同方法会失败,因为 Cake 会执行两个查询:第一个是查找所有匹配的 Invoices,然后第二个是查找具有相应外部的所有 Transactions与第一个查询的结果匹配的键:(这是它尝试运行的简化查询)

SELECT `Transaction`.* FROM `transactions` AS `Transaction`
WHERE `Invoice`.`doc_number` = `Transaction`.`doc_number`
AND `Invoice`.`date_printed` = `Transaction`.`date_printed`
AND `Invoice`.`batch_number` = `Transaction`.`batch_number`

你可以看到,它没有加入发票,所以查询死了。

关于如何完成这项工作的任何想法?

【问题讨论】:

    标签: php mysql cakephp model relationships


    【解决方案1】:

    最坏的情况,您可以使用hasMany relationship 的finderQuery 参数。它允许您完全覆盖查询。

    您还可以添加一个唯一的 id 字段,将相关数据字段合并为一个。假设您的数据库支持触发器,则 UPDATE 语句可以修复现有数据,并且可以设置 TRIGGER 在添加或更改新记录时更新它们。

    编辑:由于所有其他复杂性,您最好完全跳过 hasMany 关系并在单独的 find() 中获取交易记录。如果您必须在很多地方执行此操作,您始终可以将其包装在 Invoice 模型中的一个函数中,如下所示:

    <?php
    class Invoice extends AppModel() {
        ...
    
        function getInvoice($conditions) {
            $invoice = $this->find('first', compact('conditions'));
    
            $conditions = array(
                 'Transaction.doc_number' => $invoice['Invoice']['doc_number'],
                 'Transaction.date_printed' => $invoice['Invoice']['date_printed'],
                 'Transaction.batch_number' => $invoice['Invoice']['batch_number']);
            $invoice['transactions'] = $this->Transaction->find('all', compact('conditions'));
    
            return $invoice;
        }
    }
    ?>
    

    如果您在模型中使用类似的函数,请不要忘记 Invoice 需要定义与 Transaction 的关系,即使您不直接使用它,以便定义 $this->Transaction。

    此外,如果您更喜欢以 hasMany 关系的方式返回数据,您始终可以添加一个 foreach 循环以这种方式重新组合它们。

    更新 还有一个 SimpleResults behavior in the Cake Bakery 可以轻松地以常规 hasMany 关联的格式从其他表返回这些结果。

    【讨论】:

    • 所以我告诉 Cake 它是一个 HABTM,而它实际上是一个“hasMany”?关于这些数据的真正真正真棒消息(对我来说)是它在我的应用程序中是只读的,因此更新和触发器不会成为问题。
    • 不,应该是 hasMany,只是 finderQuery。我第一次读错了。
    【解决方案2】:
    猜你喜欢
    • 2011-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多