2

I'm trying to seed a MySql table using Laravel seeder class. The problem is that it is not assigning the id field (which is an incremental) value as I set. In the seeder class I got:

public function run()
{

    Patropi\Entidade::create([
        'id' => '0',
        'nome' => 'entidade 0',
        'cpfcnpj' => '12345678901'
    ]);

    Patropi\Fornecedor::create([
        'id' => '0',
        'prioridade' => '0'
    ]);
}

On the database, the Fornecedor table id is a foreign key which references the Entidade id, that's why I want to have the same Id on both. The problem is, when it inserts on Entidade it doesn't put it as id = 0 but instead it gives the value of the last incremental + 1. How to force laravel to insert 0 there instead? Thanks in advance.

3
  • Not clear what you need, the primary key should be "positive" like 1.. if you have 10 records you will get ids from 1 - 10. You can truncate the table before seeding to ensure keys from 1 - 10. Commented Aug 12, 2017 at 16:38
  • I want to the seeder to define the ID value. In the example, I set to the ID to be = 0, but when it adds to the table it does increment instead of setting to zero
    – Fnr
    Commented Aug 12, 2017 at 16:48
  • I think you cant set the primary key when using seeders. Why do you want to set it? If you need FK relations, seed first the primary table and query for the ids in the other seeder. Commented Aug 12, 2017 at 16:50

2 Answers 2

5

The reason why it happens is Guarding Attributes. The attributes listed in $guarded array are protected from changes, what means Laravel will ignore all your attempts to modify them. Sometimes this approach is also known as Mass Assignment Protection.

By defualt, Laravel protects "id", so you can't and don't need to set them manually, however there's a way how to stop this default behavior with an unguard() method.

Here's how you can fix your code:

public function run()
{
    Patropi\Entidade::unguard();

    Patropi\Entidade::create([
        'id' => '0',
        'nome' => 'entidade 0',
        'cpfcnpj' => '12345678901'
    ]);

    Patropi\Fornecedor::create([
        'id' => '0',
        'prioridade' => '0'
    ]);
}
2

Storing NULL or 0 in the auto-incrementing field is one of the triggers to assign the next incremental value.

From the MySQL docs:

You can also explicitly assign 0 to the column to generate sequence numbers.

If you want to disable this functionality, you can turn on the NO_AUTO_VALUE_ON_ZERO sql mode. This will change MySQL so that only assigning NULL will assign the next incremental value, and will allow you to store 0 in the field. From the docs:

NO_AUTO_VALUE_ON_ZERO affects handling of AUTO_INCREMENT columns. Normally, you generate the next sequence number for the column by inserting either NULL or 0 into it. NO_AUTO_VALUE_ON_ZERO suppresses this behavior for 0 so that only NULL generates the next sequence number.

This mode can be useful if 0 has been stored in a table's AUTO_INCREMENT column. (Storing 0 is not a recommended practice, by the way.)

If you don't explicitly need the id to be 0, then I would not try to assign 0. If the id doesn't matter, then you can do this:

public function run()
{
    $entidade = Patropi\Entidade::create([
        'nome' => 'entidade 0',
        'cpfcnpj' => '12345678901'
    ]);

    Patropi\Fornecedor::create([
        'id' => $entidade->id,
        'prioridade' => '0'
    ]);
}

Or, if you have the Eloquent relationships setup:

public function run()
{
    $entidade = Patropi\Entidade::create([
        'nome' => 'entidade 0',
        'cpfcnpj' => '12345678901'
    ]);

    // assumes fornecedor() defines a hasone/hasmany relationship.
    $entidade->fornecedor()->create([
        'prioridade' => '0'
    ]);
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.