Заполнение таблицы первичным ключом, который также является внешним ключом в Laravel

У меня есть таблица Users, которая действует как абстрактная таблица для таблиц Engineers и Architects.

Users [id (PK), first_name, last_name, role] где «роль» — это либо «Инженер», либо «Архитектор» Engineers [id (PK/FK), experience, skill_set] где иностранный «id» ссылается на «id» на «Пользователи»
Architects [id (PK/FK), certification, level] где сторонний «id» ссылается на «id» на «Пользователи»

(Атрибуты таблицы произвольны. Я просто хотел донести идею. По сути, есть две таблицы с общими атрибутами. Общие атрибуты перемещены в отдельную таблицу).

После заполнения таблицы Users мне нужно заполнить таблицу Engineers уникальным идентификатором, соответствующим таблице Users (поскольку это PK и FK), где Users.role == 'Engineer'.
То же самое нужно сделать для Architects.

Мое текущее решение состоит в том, чтобы создать пользователей, выполнить запрос, чтобы получить всех пользователей, где «роль» — «инженер», и в операторе foreach создать инженеров для каждого пользователя.

class DatabaseSeeder extends Seeder
{
    public function run()
    {
        $faker = Faker\Factory::create();

        $users = factory(App\User::class, 10)->create(); // Create Users
        $engineers = App\User::all()->where('role', 'engineer');

        foreach($engineers as $engineer){
            App\Engineer::create([
                'id' => $engineer->id,
                ...
            ]);
       }
    }
}

Как переместить App\Engineer в собственный сеялку?

Мой мыслительный процесс состоял в том, чтобы создать массив пользователей, где «роль» == «инженер». Затем вытащите пользователя и используйте User->id этого пользователя при создании инженера.

class EngineersTableSeederextends Seeder
{
    public function run()
    {
        $engineers = App\User::all()->where('role', 'engineer');
        $engineer = array_pop( $engineers );

        factory(App\Engineer::class, 10)->create()->each(function($e) {
            //$p-> ; ???
        });
    }
}

Я также пробовал это внутри EngineerFactory;

use Faker\Generator as Faker;

$factory->define(App\Engineer::class, function (Faker $faker) {

    return [
        'id' => $faker->unique()->randomElement(App\User::all()->where('roles', 'engineer')->pluck('id')->toArray()),
        ...
    ];
});

Однако из-за модификатора unique() я получаю ошибку Maximum retries of 10000 reached without finding a unique value. Это работает, если у меня около 100 пользователей, но я создаю только 10 инженеров.

Я не уверен, что это правильный подход.


person syntax error    schedule 17.10.2017    source источник


Ответы (1)


id никогда не должен быть внешним ключом, если ваш engineers должен быть связан с пользователем, создайте поле user_id в таблице engineers. Тогда ваши сеялки будут:

$users = factory(App\User::class, 10)->create(); // Create Users
$usersEngineers = App\User::all()->where('role', 'engineer');

foreach($usersEngineers as $userEngineer){
    App\Engineer::create([
        'user_id' => $userEngineer->id,
        ...
    ]);
}

Или вы можете определить свою инженерную фабрику следующим образом:

use Faker\Generator as Faker;

$factory->define(App\Engineer::class, function (Faker $faker) {

    $userEngineer = factory(App\User::class)->create();
    // some logic to assign engineer role to $userEngineer
    return [
        'user_id' => $userEngineer
        ...
    ];
});
person Lloople    schedule 18.10.2017
comment
В этом случае внешний ключ также является первичным ключом, который, как я прочитал, является допустимым шаблоном проектирования, как видно здесь. Однако, если я создам внешний ключ user_id, возможно ли, чтобы у двух инженеров был один и тот же user_id? Это может контролироваться приложением, но на уровне базы данных это не плохой дизайн? - person syntax error; 18.10.2017
comment
Вы можете сделать user_id уникальным в таблице engineers, чтобы предотвратить дублирование. - person Lloople; 18.10.2017