cakephp - belongsToMany: 允许并重用具有现有 UNIQUE 标题的关联条目
问题描述
是)我有的
我的belongsToMany关联类似于CakePHP Cookbook中的关联。但是,我已经UNIQUE
对标签标题设置了限制。
(另一个可能无关紧要的区别是,我在Tagssite_id
表中的每个标记旁边添加了一个字段,并且在和上都设置了另一个复合约束。)UNIQUE
tag
site_id
什么不起作用
提交重复的标签标题会导致错误。
当我在保存之前调试我的新文章实体时,我可以看到重复的标签标题在验证尝试后被拒绝。
'tags' => [
// This submitted tag title already exists in Tags
(int) 0 => object(App\Model\Entity\Tag) id:1 {
'site_id' => (int) 2
'[new]' => true
'[accessible]' => [
'site_id' => true,
'title' => true,
'created' => true,
'modified' => true,
'site' => true,
'articles' => true,
]
'[dirty]' => [
'site_id' => true,
]
'[original]' => [
]
'[virtual]' => [
]
'[hasErrors]' => true
'[errors]' => [
'title' => [
'unique' => 'The provided value is invalid', // ← error
],
]
'[invalid]' => [
'title' => 'test',
]
'[repository]' => 'Tags'
},
// …
// This submitted tag title does *not* already exist in Tags
(int) 3 => object(App\Model\Entity\Tag) id:4 {
'title' => 'tag'
'site_id' => (int) 2
'[new]' => true
'[accessible]' => [
'site_id' => true,
'title' => true,
'created' => true,
'modified' => true,
'site' => true,
'articles' => true,
]
'[dirty]' => [
'title' => true, // ← no error
'site_id' => true,
]
'[original]' => [
]
'[virtual]' => [
]
'[hasErrors]' => false
'[errors]' => [
]
'[invalid]' => [
]
'[repository]' => 'Tags'
},
]
我期望它如何工作?
我正在寻找的行为是如果一个标签已经存在,那么获取它的 ID 并将提交的文章条目链接到该现有 ID。所以ON DUPLICATE KEY
从某种意义上说。
是否有一个我缺少的标志可以告诉/允许 ORM 执行此操作,或者我应该开始尝试一些->epilog()
技巧?
解决方案
ORM保存过程没有这样的功能,不,你不能使用epilog()
默认的ORMsave()
过程,你必须手动创建插入查询,但是你不能真正使用实体,它不会' t 解决验证问题,您必须或多或少地手动应用验证和应用程序规则(您不想盲目地将数据插入到插入查询中,甚至是强硬的Query::values()
绑定数据)。
我可能会建议检查在编组之前修改数据的解决方案是否合适,它将透明地集成到流程中。您可以使用唯一索引列来查找现有行,并将它们的主键值注入请求数据,然后修补/编组过程将能够正确查找现有记录并相应地更新它们。
根据具体的用例,这可能比手动构建插入查询更多工作,但恕我直言,它会更好地集成。在您的特定情况下,它可能更容易,因为使用手动插入查询将需要您分别为所有不同的表插入数据,因为您不能使用 ORM 的关联保存功能和手动构造的插入查询。
最后,这里有一些未经测试的快速和肮脏的示例代码来说明这个概念:
// in ArticlesTable
public function beforeMarshal(
\Cake\Event\EventInterface $event,
\ArrayAccess $data,
\ArrayObject $options
): void {
// extract lookup keys from request data
$keys = collection($data['tags'])
->extract(function ($row) {
return [
$row['tag'],
$row['site_id'],
];
})
->toArray();
// query possibly existing rows based on the extracted lookup keys
$query = $this->Tags
->find()
->select(['id', 'tag', 'site_id'])
->where(
new \Cake\Database\Expression\TupleComparison(
['tag', 'site_id'],
$keys,
['string', 'integer'],
'IN'
)
)
->disableHydration();
// create a map of lookup keys and primary keys from the queried rows
$map = $query
->all()
->combine(
function ($row) {
return $row['tag'] . ';' . $row['site_id'];
},
'id'
)
->toArray();
// inject primary keys based on whether lookup keys exist in the map
$data['tags'] = collection($data['tags'])
->map(function ($row) use ($map) {
$key = $row['tag'] . ';' . $row['site_id'];
if (isset($map[$key])) {
$row['id'] = $map[$key];
}
return $row;
})
->toArray();
}
注入现有记录的主键后,编组、验证、规则和保存应该能够正确区分要更新的内容和要插入的内容,即您应该能够像以前一样继续使用默认的 ORM 保存过程.
也可以看看
推荐阅读
- matrix - 良好的训练和验证准确性,但混淆矩阵较差
- arrays - 二维数组的右旋转
- windows-server-2016 - Windows Server 2016 在重新启动时也将共享文件夹永久挂载为光盘
- android - 为用户创建单个帐户的 LinkWithCredentials 流程帮助
- c - OpenvVMS将char参数数组从pascal传递给C函数
- r - R - 分面饼图
- parallel-processing - CUDA 块与线程和 SMP 之间的关系
- django - 在 microsoft dynamics 内的 iframe 中打开的 django webapp 中的自动登录
- java - 如何让 GRPC 的重试机制在 Kubernetes 集群中使用 grpc-java 工作?
- distributed-computing - 无法在 Slurm 中分配 GPU