Laravel firstOrCreate方法抛出重复的ID错误

时间:2018-06-19 08:50:08

标签: laravel postgresql eloquent

我正在我的Laravel项目中编写一个命令,该命令将类别插入到数据库表中,但取决于它们是否已存在。

我调查了这样做的方法并遇到了<lvc:Axis.Separator> <lvc:Separator StrokeThickness="1" /> </lvc:Axis.Separator> 方法,所以我在我的命令中写了以下内容:

firstOrCreate

基本上,我需要在communications_categories表中创建这两个类别,区域ID为1.作业更新类别已经存在,因此它按预期跳过了它,但是当它尝试创建没有这样做的警报类别时。存在我在控制台中收到以下错误:

  

SQLSTATE [23505]:唯一违规:7错误:重复键值   违反了唯一约束&#34; communications_categories_pkey&#34;

     

详细信息:Key(id)=(2)已存在。 (SQL:插入到   &#34; communications_categories&#34; (&#34;名称&#34;,&#34; region_id&#34;,&#34; updated_at&#34;,   &#34; created_at&#34;)值(警报,1,2018-06-19 09:38:20,2018-06-19   09:38:20)返回&#34; id&#34;)

当它已经存在时,它似乎尝试分配主键ID为2 - 但是表结构在主键上有一个nextval,我认为这将添加最后一个ID并创建一个新的ID之后。根据关于Eloquent Inserts here的Laravel文档,没有提及必须规定实际的主键ID本身,并且可填充元素仅为$comCats = new CommunicationsCategories(); $comCats->firstOrCreate( ['name' => 'Job Updates'], ['region_id' => 1]); $comCats->firstOrCreate( ['name' => 'Alerts'], ['region_id' => 1]); name。< / p>

对此的任何帮助都表示赞赏,因为我对Laravel和eloqent数据库方法都相当新。如果有帮助,我会使用PostgreSQL数据库。

3 个答案:

答案 0 :(得分:0)

firstOrCreate方法将尝试使用给定的列/值对定位数据库记录。如果在数据库中找不到该模型,则将插入一条记录,其中包含第一个参数的属性以及可选的第二个参数中的属性。

$comCats->firstOrCreate(
    ['name' => 'Job Updates'], ['region_id' => 1]);

在这里,您尝试首先找到带有“作业更新”的name和带有1的region_id,如果laravel无法找到特定数据,它将尝试创建或插入给定参数,但是当系统尝试插入时,已存在值为“1”的region_id

如果region_id是您的主键,请尝试:

  $comCats->firstOrCreate(
        ['name' => 'Job Updates']);

答案 1 :(得分:0)

另一个答案似乎是假设您需要先向firstOrCreate进行解释,而实际上您实际上在Laravel框架中遇到了一个错误,并且还假设Key (id)=(2)指向region_id您的自动递增主键id

您很可能希望在communications_categories.name上使用唯一索引。

您可以改为在postgres中使用此SQL(假设名称上具有唯一索引),它应该比firstOrCreate更可靠,但是如果您打算将其他laravel功能与firstOrCreate配合使用(例如观察者,或更多查询生成器) ,它们的功能可能会丢失。

    INSERT INTO communications_categories (name, region_id, created_at, updated_at)
    VALUES ('Job Updates', 1, NOW(), NOW())
    ON CONFLICT (name) DO
    UPDATE SET region_id = excluded.region_id,
        updated_at = NOW()
    RETURNING *;

可以这样使用:

    $values = DB::select($sql); // will return Array of StdClass

,如果您不需要returning *值,则不使用id

    DB::insert($sql); // will return true

如果您需要返回Eloquent对象,建议使用returning *returning id并将其传递给CommunicationsCategories::findOrFail($values[0]['id'])。将复杂的insert语句放入Eloquent select中可能会花费很多工作。 Eloquent还具有一个称为hydr的函数,该函数无需其他SQL调用即可工作。

该SQL语句将插入所需的值,除非唯一约束存在冲突,然后它将通过更新将插入中从冲突中排除的值应用于先前存在的行。

答案 2 :(得分:0)

请原谅我还不能发表评论...

如果有人遇到关于 postgresql 的同样问题,这绝对是一个错误。在我的情况下,此错误发生在我按照以下过程使用 heroku 导入本地 postgresql 数据库之后:

Workaround for pushing to heroku database on windows machince.

我尝试再次运行查询,它奏效了……有时也会失败。现在这很糟糕。我会更新这个我找到了解决这个问题的另一种方法。

编辑: 在查看了有关该问题的更多搜索后,我发现以下内容与我的情况完全匹配:

PostgreSQL: Unique violation: 7 ERROR: duplicate key value violates unique constraint “users_pkey”