CakePHP:无法通过 belongsTo 关联的子实体将数据保存到父实体
CakePHP: Unable to save data to parent entity via belongsTo associated child
问题描述
我正在尝试配置 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]: Not null violation: 7 ERROR: null value in column 'person_id' violates not-null constraint
DETAIL: Failing row contains (1, null, foo, bar)
我知道这是因为 Cake 试图保存到 Users
而没有 person_id
来满足外键约束。在我的应用程序域中无法扭转这种 FK 关系,因为我们需要向左的一对多关系(用户 -> 1 人)。
我怀疑在 JSON
负载的 persons
对象中发送一个 id
可以正确保存。但是,由于各种原因,这在运行时是不可能的。例如,这是它在 "Saving Data" CakePHP Book page...
中的显示方式
$data = [
'title' => 'First Post',
'user' => [
'id' => 1,
'username' => 'mark'
]
];
...
$article = $articles->newEntity($data, [
'associated' => ['Users']
]);
$articles->save($article);
我知道对于类似的问题,下面的也可能像 一样工作,因为 Persons
可以保存到 Users
,但与我的相比感觉不太合适'我正在尝试做,感觉好像有一种方法可以通过 Users
.
上的关联
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);
...
工作原理
现在我相信这在 CakePHP 2.X 中曾经是可能的,正如 this answer by ndm 在一个类似的问题中所述,有人试图保存 belongsTo
关联的实体并且它是通过 belongsTo
实体在一个请求中包含父 hasOne
实体。
That's the expected behavior, saveAssociated() is not meant to save only the associated records, it will save the main record as well, so you should use saveAssociated() only, no need to manually set the foreign key, etc, CakePHP will do that automatically.
Controller
public function create() {
if ($this->request->is('post') && !empty($this->request->data)):
$this->CandidatesProblemReport->create();
if ($this->CandidatesProblemReport->saveAssociated($this->request->data)):
// ...
endif;
endif;
}
但是,在文档中,我无法在 Users
实体继承自的 Cake\ORM\Table
对象上找到或使用 saveAssociated()
方法。调用它会产生找不到方法的错误。此方法似乎仅存在于 Cake\ORM\Association
对象上,如 documentation 中所述。除非我遗漏了明显的东西,否则有没有办法使用它,或者它是否被 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)
尝试 \Cake\Log\Log::error($savedEntity);
日志文件中没有显示任何内容。
save()
协会参数
我考虑的另一种解决方案是使用 save()
的 $options['associated]
,如 documentation 所示(摘录如下)。如下所示将此设置为 true 后,错误仍然发生。
save( Cake\Datasource\EntityInterface $entity , array $options [] )
... associated: If true it will save 1st level associated entities as they are found in the passed $entity whenever the property defined for the association is marked as dirty. If an array, it will be interpreted as the list of associations to be saved. It is possible to provide different options for saving on associated table objects using this key by making the custom options the array value. If false no associated records will be saved. (default: true) ...
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
并利用其 hasOne
关系,我的 Users
和 Persons
数据无法通过 UsersController.php
。
如果我遗漏了任何重要信息,或者您还有 questions/need 更多信息,请询问!我可能错过了一些明显的东西,但我很感激任何可能的 suggestions/solutions。
正如@ndm 指出的那样,错误在于发布的数据。根据文档的 "Saving Data: Saving BelongsTo Associations" 页面:
When saving belongsTo associations, the ORM expects a single nested entity named with the singular, underscored version of the association name.
发布的密钥 persons
应该是 person
。同样,如果实体被命名为 PersonSnapshots
,则水化到实体中的有效负载中的相关密钥需要是 person_snapshot
.
问题描述
我正在尝试配置 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]: Not null violation: 7 ERROR: null value in column 'person_id' violates not-null constraint DETAIL: Failing row contains (1, null, foo, bar)
我知道这是因为 Cake 试图保存到 Users
而没有 person_id
来满足外键约束。在我的应用程序域中无法扭转这种 FK 关系,因为我们需要向左的一对多关系(用户 -> 1 人)。
我怀疑在 JSON
负载的 persons
对象中发送一个 id
可以正确保存。但是,由于各种原因,这在运行时是不可能的。例如,这是它在 "Saving Data" CakePHP Book page...
$data = [
'title' => 'First Post',
'user' => [
'id' => 1,
'username' => 'mark'
]
];
...
$article = $articles->newEntity($data, [
'associated' => ['Users']
]);
$articles->save($article);
我知道对于类似的问题,下面的也可能像 Persons
可以保存到 Users
,但与我的相比感觉不太合适'我正在尝试做,感觉好像有一种方法可以通过 Users
.
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);
...
工作原理
现在我相信这在 CakePHP 2.X 中曾经是可能的,正如 this answer by ndm 在一个类似的问题中所述,有人试图保存 belongsTo
关联的实体并且它是通过 belongsTo
实体在一个请求中包含父 hasOne
实体。
That's the expected behavior, saveAssociated() is not meant to save only the associated records, it will save the main record as well, so you should use saveAssociated() only, no need to manually set the foreign key, etc, CakePHP will do that automatically.
Controller
public function create() { if ($this->request->is('post') && !empty($this->request->data)): $this->CandidatesProblemReport->create(); if ($this->CandidatesProblemReport->saveAssociated($this->request->data)): // ... endif; endif; }
但是,在文档中,我无法在 Users
实体继承自的 Cake\ORM\Table
对象上找到或使用 saveAssociated()
方法。调用它会产生找不到方法的错误。此方法似乎仅存在于 Cake\ORM\Association
对象上,如 documentation 中所述。除非我遗漏了明显的东西,否则有没有办法使用它,或者它是否被 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)
尝试 \Cake\Log\Log::error($savedEntity);
日志文件中没有显示任何内容。
save()
协会参数
我考虑的另一种解决方案是使用 save()
的 $options['associated]
,如 documentation 所示(摘录如下)。如下所示将此设置为 true 后,错误仍然发生。
save( Cake\Datasource\EntityInterface $entity , array $options [] )
... associated: If true it will save 1st level associated entities as they are found in the passed $entity whenever the property defined for the association is marked as dirty. If an array, it will be interpreted as the list of associations to be saved. It is possible to provide different options for saving on associated table objects using this key by making the custom options the array value. If false no associated records will be saved. (default: true) ...
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
并利用其 hasOne
关系,我的 Users
和 Persons
数据无法通过 UsersController.php
。
如果我遗漏了任何重要信息,或者您还有 questions/need 更多信息,请询问!我可能错过了一些明显的东西,但我很感激任何可能的 suggestions/solutions。
正如@ndm 指出的那样,错误在于发布的数据。根据文档的 "Saving Data: Saving BelongsTo Associations" 页面:
When saving belongsTo associations, the ORM expects a single nested entity named with the singular, underscored version of the association name.
发布的密钥 persons
应该是 person
。同样,如果实体被命名为 PersonSnapshots
,则水化到实体中的有效负载中的相关密钥需要是 person_snapshot
.