【问题标题】:How to fix upsert problem when seeding? (laravel)播种时如何解决upsert问题? (拉拉维尔)
【发布时间】:2021-07-31 12:18:54
【问题描述】:

我在下面有这些代码,似乎一切正常,但是当我尝试运行单元测试时,它在下面返回错误。


这是我的播种机(这个播种机在不同的测试用例中被多次调用)

DB::table('sizes')->upsert([
    [
        'name' => 'jumbo',
        'created_at' => date("Y-m-d H:i:s"),
        'updated_at' => date("Y-m-d H:i:s"),
    ],
    [
        'name' => 'large',
        'created_at' => date("Y-m-d H:i:s"),
        'updated_at' => date("Y-m-d H:i:s"),
    ]
], ['id'], ['name']);

然后错误弹出:

Illuminate\Database\QueryException:SQLSTATE[23000]:完整性约束违规:19 UNIQUE 约束失败:sizes.name(SQL:插入“sizes”(“created_at”、“name”、“updated_at”)值(2021 -05-10 12:52:18, 巨型, 2021-05-10 12:52:18), (2021-05-10 12:52:18, large, 2021-05-10 12:52:18) on冲突(“id”)做更新集“名称”=“排除”。“名称”)

这里是迁移:

Schema::create('sizes', function (Blueprint $table) {
    $table->id();
    $table->string('name')
          ->unique();
    $table->timestamps();
});

【问题讨论】:

  • 请显示您的架构
  • @ThaiNguyenHung 更新描述
  • 在您的 upsert 查询中,“name”是唯一字段而不是“id”,在您的 upsert 查询旁边不更新任何字段,因此您可以删除第三个参数 DB::table('sizes')- > ->upsert([ [ 'name' => 'jumbo', 'created_at' => date("Ymd H:i:s"), 'updated_at' => date("Ymd H:i:s"), ], [ 'name' => 'large', 'created_at' => date("Ymd H:i:s"), 'updated_at' => date("Ymd H:i:s"), ] ], [ '名称']);

标签: laravel laravel-seeding


【解决方案1】:

您的迁移将产生这样的表:

id INT AUTO_INCREMENT PRIMARY_KEY
name VARCHAR UNIQUE
created_at TIMESTAMP
updated_at TIMESTAMP

你的播种机第一次运行时会插入这样的记录:

id name created_at updated_at
1 jumbo ... ...
2 large ... ...

现在,根据 laravel 关于 upsert 的文档:

If you would like to perform multiple "upserts" in a single query, then you should use the upsert method instead. 
The method's first argument consists of the values to insert or update, while the second argument lists the column(s) that uniquely identify records within the associated table. 
The method's third and final argument is an array of the columns that should be updated if a matching record already exists in the database. 
The upsert method will automatically set the created_at and updated_at timestamps if timestamps are enabled on the model:

重点是:

The method's first argument consists of the values to insert or update, 
while the second argument lists the column(s) that uniquely identify records within the associated table. 
The method's third and final argument is an array of the columns that should be updated if a matching record already exists in the database

也就是说,你的命令:

DB::table('sizes')->upsert([
    [
        'name' => 'jumbo',
        'created_at' => date("Y-m-d H:i:s"),
        'updated_at' => date("Y-m-d H:i:s"),
    ],
    [
        'name' => 'large',
        'created_at' => date("Y-m-d H:i:s"),
        'updated_at' => date("Y-m-d H:i:s"),
    ]
], ['id'], ['name']);

会这样做:

  • 检查是否有任何记录的 id 为(空白)=> 没有记录将匹配(因此 upsert 将变为插入)
  • 插入数据库,值名称=jumbo,并插入数据库,值名称=大,
    • 第二步将失败,因为数据库中已经有 name=jumbo 的记录(以及另一个 name=large 的记录)
    • 记住你有name VARCHAR UNIQUE约束,这第二步违反了UNIQUE约束

相反,您应该将播种机更改为:

DB::table('sizes')->upsert([
    [
        'name' => 'jumbo',
        'created_at' => date("Y-m-d H:i:s"),
        'updated_at' => date("Y-m-d H:i:s"),
    ],
    [
        'name' => 'large',
        'created_at' => date("Y-m-d H:i:s"),
        'updated_at' => date("Y-m-d H:i:s"),
    ]
], ['name'], ['created_at','updated_at']);

编辑后的版本会这样做:

  • 检查是否有记录名称为“jumbo”
    • 最初不会匹配任何记录(因此 upsert 将成为第一次插入),
    • 并且后续运行将匹配(因此 upsert 将成为后续运行的更新)

【讨论】:

  • 我刚刚阅读了 Laravel 中的文档,是的,我明白了。感谢您提供更详细的信息。
猜你喜欢
  • 2017-08-22
  • 2018-03-22
  • 1970-01-01
  • 2018-11-01
  • 2018-08-26
  • 2020-08-27
  • 1970-01-01
  • 2021-05-21
  • 1970-01-01
相关资源
最近更新 更多