蛋糕 3:如何向设置了主键的数据库添加新实体?

Cake 3: How to add new entity to database with primaryKey set?

我想用从 excel sheet 中提取的 'flat' 数据填充我的数据库。所有记录都以数组形式提供(类似于 $request->data),但它们的主键设置了必须保留的值。 我的代码:

$imported = 0;  
foreach ($data as $record) {  
    $entity = $table->findOrCreate([$table->primaryKey() => $record[$table->primaryKey()]]);  
    $entity = $table->patchEntity($entity, $record);  
    if ($table->save($entity)) {  
        $imported++;  
    }  
}  

代码可以运行,但我想知道是否有更好的解决方案?

澄清一下:我想要的是添加类似

的内容
 [  
  ['id' => 25, 'title'=>'some title'],   
  ['id'=> 3, 'title' => 'some other title'],  
  ['id' => 4356,  'title' => 'another title']  
]  

到我的空数据库。 findOrCreate() 完成这项工作。但我认为没有必要在插入之前测试数据库中不存在的每条记录。

如果您真的只使用空表,那么您可以直接保存数据,无需查找和修补,只需禁用存在性检查即可保存。

另外,从您的代码来看,数据的格式似乎可以立即转换为实体,因此您可能希望一次创建它们。

$entities = $table->newEntities($data, [
    // don't forget to restrict assignment one way or
    // another when working with external input, for
    // example by using the `fieldList` option
    'fieldList' => [
        'id',
        'title'
    ]
]);

// you may want to check the validation results here before saving

foreach ($entities as $entity) {
    if ($table->save($entity, ['checkExisting' => false])) {
        // ...
    }
    // ...
}

另见

记录神秘地丢失了一些提供给新 Entity 的数据的一个常见问题是实体没有将相关字段定义为 _accessible

Cake 的 BakeShell 会在为您生成新实体 classes 时跳过主键字段,例如:

<?php
namespace App\Model\Entity;

use Cake\ORM\Entity;

/**
 * Widget Entity.
 */
class Widget extends Entity {

    /**
     * Fields that can be mass assigned using newEntity() or patchEntity().
     *
     * @var array
     */
    protected $_accessible = [
        // `id` is NOT accessible by default!
        'title' => true,
    ];
}

有几种方法可以解决这个问题。

您可以修改您的实体 class 以使 id 字段永久 可分配:

    protected $_accessible = [
        'id' => true, // Now `id` can always be mass-assigned.
        'title' => true,
    ];

或者您可以调整对 newEntity() 的调用以禁用批量分配保护:

$entities = $table->newEntity($data, [
    'accessibleFields' => ['id' => true],
]);

我发现,当您遇到 Cake 3 DB 数据问题时,最重要的收获是在创建或修补实体后立即仔细检查实体,并将其与您的输入数据进行比较。你仍然需要有敏锐的眼光,但这样做会发现实体根本没有设置 ->id 属性,即使 $data 定义了它们。