【问题标题】:$this->Model->id not working before saveAll in CakePHP$this->Model->id 在 CakePHP 中 saveAll 之前不起作用
【发布时间】:2012-10-01 22:39:30
【问题描述】:

我在 CakePHP 2 中有以下代码:

$this->Order->id = 5;
$this->Order->saveAll(array(
    'Order' => array(
        'person_id' => $this->Session->read('Person.id'),
        'amount' => $total,
        'currency_id' => $code                   
    ),
    'Lineitem' => $lineitems  /* a correctly-formatted array */
));

我希望这会更新 Order 表中主键为 5 的行,然后插入 order_id 为 5 的 Lineitem 行。

但是,它所做的只是在 Order 中创建一个新行,然后使用新 Order 记录中的新 ID 创建 Listitem 行。

注意:我只是将 ID 设置为上述目的,以方便调试和演示这个问题。在我的最终代码中,我将检查当前person_id 是否已经存在挂单,如果有则执行$this->Order->id = $var;,如果没有则执行$this->Order->create();

换句话说,有时我会希望它插入(在这种情况下我会发出$this->Order->create();),有时我会希望它更新(在这种情况下我会发出$this->Order->id = $var;)。上面的测试用例应该产生一个 UPDATE 但它却产生了一个 INSERT。

知道我在这里做错了什么吗?

【问题讨论】:

    标签: php cakephp


    【解决方案1】:

    你传递给Model->saveAll() 的数组不包含订单的id,所以Cake 创建了一个新的。如果您想更新现有记录,您可以在传递的数组中设置订单 ID,或者使用查找来检索它。 The documentation 明确备注

    如果您想更新一个值,而不是创建一个新值,请确保 您正在将主键字段传递到数据数组中

    $order = $this->Order->findById(5);
    // ... modify $order if needed
    $this->Order->saveAll(array('Order' => $order, 'LineItem' => $items));
    

    在您的情况下,您可能希望尽可能简洁地使用以下内容。 Model::saveAssociated() 足够聪明,可以根据id 创建或更新,但您必须提供合适的输入。 Model::read($fields, $id) 初始化内部 $data:对于现有记录,所有字段都将从数据库中读取,但对于不存在的 id,您需要提供正确的数据才能成功。假设订单belongsTo 客户,如果订单不存在,我提供客户 ID

    // set the internal Model::$data['Order']
    $this->Order->read(null, 5);
    // You may want to supply needed information to create
    // a new order if it doesn't exist, like the customer
    if (! $this->Order->exists()) {
        $this->Order->set(array("Customer" => array("id" => $customer_id)));
    }
    $this->Order->set(array('LineItem' => $items));
    $this->Order->saveAssociated();
    

    最后一点,您似乎正在实现一个购物车。如果是这种情况,也许使用单独的ShoppingCart 而不是带有finalized 标志的Order 会更清楚。

    【讨论】:

    • 但是如果我这样做了,如果没有 id 就会中断,除非我创建了两个单独的 saveAll 命令(一个有,一个没有)并将它们放在一个条件语句中,这似乎是不必要的重复大部分代码。根据手册(book.cakephp.org/2.0/en/models/…),您可以通过事先执行$this->Model->id = 5 来强制更新。
    • @Joseph ,您链接的同一段声明 如果您想更新一个值,而不是创建一个新值,请确保您将主键字段传递到数据数组中
    • 是的,但这也意味着首先调用$this->Model->id = 5 会做到这一点,将主键字段传递到数据数组中。
    • 我听不懂你。您不必相信我,但如果您的代码不起作用...$this->Model->id 设置内部Model::$data 的ID。不幸的是,这个数组没有与传递给Model::saveAssociated($data) 的数组合并。 Look at the sources(或使用调试器)。我真的不明白你为什么不喜欢我的解决方案:它简单、简洁且有效
    • 抱歉,并不是我不喜欢你的回答,只是我从文档中了解到$this->Model->id = 5 应该做我想做的事,而实际上它不应该做。无论如何,我刚刚实施了您的解决方案,它运行良好,非常感谢!也感谢您关于制作单独的ShoppingCart 的其他建议——您能否指出模型之间如何关联的任何示例。我不能立即明白为什么它会是一种更好的方法,但如果我看到一个例子,它可能会变得很清楚。再次感谢!
    【解决方案2】:

    您是否尝试过以下操作:

    $this->Order->saveAll(array(
        'Order' => array(
            'id' => 5,
            'person_id' => $this->Session->read('Person.id'),
            'amount' => $total,
            'currency_id' => $code                   
        ),
    'Lineitem' => $lineitems  /* a correctly-formatted array */
    ));
    

    这和你做的差不多:

    $this->Order->id = 5;
    

    也许这可以解决您的问题。 Cake 正在检查你是否设置了 id 字段,如果它在那里更新记录,如果没有找到它会创建新记录。

    更新: 然后可能在 saveAll 之前检查是否有 id 字段,然后将检查结果保存到某个布尔值并创建数组以保存由该布尔值确定,例如:

    if($id_exist) $order['Order']['id'] = 5;
    $order['Order']['id'] = 5;
    $order['Order']['person_id'] = $this->Session->read('Person.id'),
    $order['Order']['amount'] = $total;
    $order['Order']['currency_id'] = $code;
    
        $this->Order->saveAll(array(
        'Order' => $order,
    'Lineitem' => $lineitems  /* a correctly-formatted array */
    ));
    

    【讨论】:

    • 是的,那肯定行得通。但是在每种情况下都不会有一个 id,我实际上想要一个 INSERT。我已经更新了问题以使其更清晰。
    • 我已经更新了答案,以便它涵盖您的 id 不存在并且您希望插入记录的情况。
    • 感谢您花时间更新您的答案。它运行良好,但我选择了 Raffaele 的解决方案,因为代码更简洁。
    猜你喜欢
    • 2011-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-17
    相关资源
    最近更新 更多