Laravel 在事务内插入父子失败

问题描述 投票:0回答:6

我正在尝试执行 2 次插入,在 2 个表中,表通过外键受到约束。这两个操作必须在事务内执行,以防止最终失败。 (实际上,我需要在更多表上执行更多插入,因此事务很重要;但本示例中的 2 个表足以复制问题)

数据库驱动程序是pgsql

SomeRepo.php(也尝试使用事务关闭变体)

        DB::beginTransaction();
        try {
            $parentData = [
                'name' => 'Parent name'
            ];
            $parent = new Parent($parentData);
            $parent->save();

            $childData = [
                // Tried it with and without setting "parent_id" here
                'parent_id' => $parent->id,
                'name' => 'Child name'
            ];
            $child = new Child($childData);
            $parent->children()->save($child);
            DB::commit();
        } catch (Exception $e) {
            DB::rollback();
        }

Parent.php

    protected $fillable = [
        'name'
    ];

    public function children()
    {
        return $this->hasMany(Child::class);
    }

Child.php

    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;
php laravel postgresql transactions foreign-keys
6个回答
0
投票

要将数据保存在相关表中,请使用此

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.',
    ],
]);

0
投票

通过在父模型的关系上使用

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',
    ],
]);

0
投票

你可以试试这个

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();
 }

0
投票

更改外键——在数据库上运行此sql

alter table child drop constraint child_parent_id;

alter table child add foreign key (parent_id) references parent(id) deferrable initially deferred;

这将允许您以任意顺序创建子级或父级,并且在提交之前约束不会被验证。在这种情况下,这不是必需的——但是,这确实取决于您的 ID 的生成方式。


0
投票

我没有测试,但我认为数据库方法 'DB::table('---')->insert()' 可以适合您的情况


-1
投票

children 函数需要一个中间表,将其更改为:

 public function children()
{
    return $this->belongsToMany(Child::class);
}

并且不要这样做

$parent->children()->save($child);

或者如果您想这样做,请制作

child_parent
表,其中包含 2 个字段
child_id
parent_id

© www.soinside.com 2019 - 2024. All rights reserved.