繁体   English   中英

Laravel 插入父子在事务内部失败

[英]Laravel inserting parent child fails inside transaction

我正在尝试执行 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();
        }

父.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;

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

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

通过在父 model 的关系上使用createcreateMany来尝试使用此代码:

// 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 是如何生成的。

儿童 function 需要一个中间表将其更改为:

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

不要这样做$parent->children()->save($child); .

或者,如果您想 go 那样制作child_parent表,其中包含 2 个字段child_idparent_id

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM