Php Laravel在事务内插入父级子级失败
我正在尝试执行2个插入,在2个表中,表通过外键进行约束。这两个操作必须在事务内部执行,以防止最终失败。(实际上,我需要在更多的表上执行更多的插入操作,因此事务非常重要;但本例中的2个表足以复制问题) 数据库驱动程序是pgsql SomeRepo.php(也尝试使用事务关闭变量) Parent.phpPhp Laravel在事务内插入父级子级失败,php,laravel,postgresql,transactions,foreign-keys,Php,Laravel,Postgresql,Transactions,Foreign Keys,我正在尝试执行2个插入,在2个表中,表通过外键进行约束。这两个操作必须在事务内部执行,以防止最终失败。(实际上,我需要在更多的表上执行更多的插入操作,因此事务非常重要;但本例中的2个表足以复制问题) 数据库驱动程序是pgsql SomeRepo.php(也尝试使用事务关闭变量) Parent.php protected $fillable = [ 'name' ]; public function children() { ret
protected $fillable = [
'name'
];
public function children()
{
return $this->hasMany(Child::class);
}
protected $fillable = [
'name', 'parent_id'
];
Child.php
protected $fillable = [
'name'
];
public function children()
{
return $this->hasMany(Child::class);
}
protected $fillable = [
'name', 'parent_id'
];
尝试插入返回父id的子行时执行失败
insert or update on table "child" violates foreign key constraint "child_parent_id_foreign"
编辑
子表SQL:
DROP TABLE IF EXISTS "public"."child";
CREATE TABLE "public"."child" (
"id" int4 NOT NULL DEFAULT nextval('child_id_seq'::regclass),
"parent_id" int4 NOT NULL,
"is_read" bool NOT NULL DEFAULT false,
"created_at" timestamp(0) DEFAULT now(),
"updated_at" timestamp(0),
"deleted_at" timestamp(0)
)
;
ALTER TABLE "public"."child" OWNER TO "my_user";
-- ----------------------------
-- Primary Key structure for table child
-- ----------------------------
ALTER TABLE "public"."child" ADD CONSTRAINT "child_pkey" PRIMARY KEY ("id");
-- ----------------------------
-- Foreign Keys structure for table child
-- ----------------------------
ALTER TABLE "public"."child" ADD CONSTRAINT "child_parent_id_fkey" FOREIGN KEY ("parent_id") REFERENCES "public"."parent" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED;
子函数需要一个中间表将其更改为:
public function children()
{
return $this->belongsToMany(Child::class);
}
不要这样做$parent->children()->save($child)代码>
或者,如果您想这样做,请使用带有两个字段的child\u id
和parent\u id
将数据保存在相关表中
Parent::create(['name'=>'parent name']); //save in parent table
$lastId = Parent::query()->max('id'); //get last inserted row id
$parent = App\Parent::find($lastId);
$child = $parent->children()->create([
'message' => 'A new comment.',
]);
您还可以使用createMany
方法
$parent = App\Parent::find($lastId);
$parent->children()->createMany([
[
'message' => 'A new comment.',
],
[
'message' => 'Another new comment.',
],
]);
在父模型的关系上使用create
和createMany
使用此代码进行尝试:
// Create the parent object.
$parent = Parent::create([
'name' => 'Parent 1'
]);
// Insert one.
$child = $parent->children()->create([
'name' => 'Child 1',
]);
// Insert many.
$parent->children()->createMany([
[
'name' => 'Child 2',
],
[
'name' => 'Child 3',
],
]);
你可以试试这个
try {
DB::beginTransaction();
$parent = Parent::create([
'name' => 'Parent name'
]);
$parent->children()->create([
'parent_id' => $parent->id,
'name' => 'Child name'
]);
DB::commit();
} catch (Exception $e) {
DB::rollback();
}
更改外键--在数据库上运行此sql
alter table child drop constraint child_parent_id;
alter table child add foreign key (parent_id) references parent(id) deferrable initially deferred;
这将允许您按任意顺序创建子项或父项,并且在提交之前不会验证约束。在这种情况下不需要这样做,但这取决于id的生成方式。我的场景使用一对多。如果多对多关系没有用处,我不想实现它。为什么要使用最后一个id来获取父模型?根据雄辩的文档()Parent::create()
返回创建的模型,因此不需要这两行额外的代码(因为使用的最后一个id不是100%安全的,所以很危险)。不需要查询最大id。尝试了你的代码,它给出了相同的外键错误。您是否尝试在PostgreSQL数据库上运行它?如果没有事务,这肯定会起作用。但正如您在原始问题中所看到的,我需要使用PostgreSQL数据库在事务中完成所有操作。您能告诉我们数据库的结构吗?我认为这是一个鸡和蛋的问题,即在PostgreSQL中插入带有循环引用的表时,请尝试在->save()之后转储$parent->id。。。确保数据确实存在。请阅读此问题的注释,然后您也可以检查此代码与原始问题中的代码有何不同?我已经尝试过了,但仍然出现相同的错误:insert或update on table“child”违反外键约束“child\u parent\u id\u fkey”↵详细信息:表“parent”中不存在键(parent_id)=(254)
我的id由以下序列生成:默认值:nextval('parent_id_seq'::regclass)
检查子表上的外键。也许这是错误的。您可以在DDL(用于创建外键的SQL)中粘贴外键约束吗?不是这样,就是插入的数据不正确。。也就是说,子表插入不是插入您刚才创建的父键。这实际上更有意义,因为如果您以正确的顺序创建此数据,通常不必执行延迟约束,而且根据您的来源,您是。我使用用于创建子表的SQL更新了此问题。我还记录了创建的父表的id,它与在返回FK错误的子表上执行的插入中存在的父表id字段相匹配。