我正在尝试配置CakePHP 3.7 API以以子优先的方式保存关联的数据。为了举例说明,我们将实体称为Users
和Persons
-它们之间的关系如下:
UsersTable.php
...
$this->belongsTo('Persons', [
'foreignKey' => 'person_id',
'joinType' => 'LEFT',
'className' => 'MyPlugin.Persons',
]);
...
PersonsTable.php
$this->hasOne('Users', [
'foreignKey' => 'person_id',
'className' => 'MyPlugin.Users'
]);
在各自的实体中,彼此各自的属性可见性设置为true
。我想做的是POST
到/users/
路由(UsersController.php
),并保存其中的Persons
对象。负载是这样的:
{
"username": "foo",
"password": "bar",
"persons": {
"dob": "1982-07-03",
}
}
下面是保存方法的相关部分,摘自UsersController.php
:
if ($this->request->is('post') && !empty($this->request->getData())) {
$data = $this->request->getData();
$newEntity = $this->Users->newEntity($data, ['associated' => 'Persons']);
$savedEntity = $this->Users->save($newEntity);
...
这会产生以下SQL错误。
PDOException:SQLSTATE [23502]:不为null违反:7错误:“ person_id”列中的null值违反了非null约束 详细信息:失败行包含(1,null,foo,bar)
我了解这是因为Cake试图保存到Users
而没有person_id
来满足外键约束。在我们的应用程序域中,无法扭转这种FK关系,因为我们需要向左的一对多关系(用户-> 1人)。
我怀疑在有效载荷id
的{{1}}对象中发送persons
可以使此正确保存。但是,由于各种原因,这在运行时是不可能的。例如,这就是"Saving Data" CakePHP Book page ...
JSON
我知道以下类似问题也可能像suggested by xPfqHZ一样起作用,因为$data = [
'title' => 'First Post',
'user' => [
'id' => 1,
'username' => 'mark'
]
];
...
$article = $articles->newEntity($data, [
'associated' => ['Users']
]);
$articles->save($article);
可以保存到Persons
,但是与我尝试的内容相比,它不适合做,并且感觉好像有一种通过Users
上的关联的方法。
Users
现在,我相信这在CakePHP 2.X中曾经是可能的,如this answer by ndm所述,在一个类似的问题上,一个人试图保存 if ($this->request->is('post') && !empty($this->request->getData())) {
$data = $this->request->getData();
$newEntity = $this->Users->Persons->newEntity($data, ['associated' => 'Persons']);
$savedEntity = $this->Users->Persons->save($newEntity);
...
关联实体及其父{{1 }}实体通过belongsTo
实体的一个请求。
这是预期的行为,saveAssociated()并不意味着只保存相关记录,它也会保存主记录,因此您只应使用saveAssociated(),而无需手动设置外键,等等。 CakePHP将自动执行该操作。
控制器
hasOne
但是,我无法在文档中的belongsTo
实体所继承的public function create() {
if ($this->request->is('post') && !empty($this->request->data)):
$this->CandidatesProblemReport->create();
if ($this->CandidatesProblemReport->saveAssociated($this->request->data)):
// ...
endif;
endif;
}
对象上找到或使用saveAssociated()
方法。调用它会产生方法未找到错误。如documentation中所述,此方法似乎仅存在于Cake\ORM\Table
对象上。除非我没有遗漏,否则Users
及其同级方法是否可以使用它?或者内部使用它?
使用Cake\ORM\Association
或BelongsTo()
显示有效载荷的Cake\Log\Log::error($newEntity);
数据被水化为一个对象,但是我看不到附加了die(var_dump($newEntity));
对象(请参见下文)。
Users
尝试Persons
在日志文件中什么都没有显示。
object(MyPlugin\Model\Entity\User)[299]
public 'username' => string 'foo' (length=3)
public 'password' => string 'bar' (length=3)
public '[new]' => boolean true
public '[accessible]' =>
array (size=5)
'*' => boolean false
'person_id' => boolean true
'username' => boolean true
'password' => boolean true
'person' => boolean true
public '[dirty]' =>
array (size=2)
'username' => boolean true
'password' => boolean true
public '[original]' =>
array (size=0)
empty
public '[virtual]' =>
array (size=0)
empty
public '[hasErrors]' => boolean false
public '[errors]' =>
array (size=0)
empty
public '[invalid]' =>
array (size=0)
empty
public '[repository]' => string 'MyPlugin.Users' (length=17)
关联参数我考虑的另一种解决方案是使用documentation中所示的\Cake\Log\Log::error($savedEntity);
的{{1}}(如下所示)。将此设置为true时,如下所示,仍然发生错误。
保存(Cake \ Datasource \ EntityInterface $ entity,数组$ options [])
... associated :如果为true,则只要为关联定义的属性标记为脏,它将保存在传递的$ entity中找到的第一级关联实体。如果是数组,它将被解释为要保存的关联列表。通过使自定义选项成为数组值,可以使用此键提供用于保存关联表对象的不同选项。如果为false,则不会保存任何关联记录。 (默认值:true)...
save()
:
$options['associated]
如果不经历save()
并利用其UsersController.php
关系,我的 if ($this->request->is('post') && !empty($this->request->getData())) {
$data = $this->request->getData();
$newEntity = $this->Users->newEntity($data, ['associated' => 'Persons']);
$savedEntity = $this->Users->save($newEntity, ['associated' => true]);
...
和PersonsController.php
数据通过{{1 }}。
如果我错过了任何重要信息,或者您有其他疑问/需要其他信息,请询问!我可能错过了一些显而易见的事情,但我可能会提出任何建议/解决方案。
答案 0 :(得分:0)
如@ndm所示,错误在于发布的数据中。按照文档的"Saving Data: Saving BelongsTo Associations"页:
在保存belongsTo关联时,ORM希望使用一个嵌套的实体,该关联实体的名称为关联名称的单,加下划线版本。
他们发布的密钥persons
应该是person
。同样,如果将实体命名为PersonSnapshots
,则水合到实体中的有效载荷中的相关密钥将必须为person_snapshot
。