Laravel 7, SQLSTATE [23000]: нарушение ограничения целостности: 19 Не удалось выполнить ограничение NOT NULL при попытке добавить отношение - PullRequest
1 голос
/ 11 марта 2020

Я работаю Laravel 7 на PHP 7.4 с MySQL 8.0.

У меня есть три таблицы, User, Company и Department, с соответствующими моделями и фабрики.

Я создал тест, в котором я добавляю связь:

// MyTest.php
$user = factory(User::class)->create();

$company = factory(Company::class)->make();
$company->user()->associate($user);
$company->create(); // it fails here because of NOT NULL constraint, companies.user_id

$department = factory(Department::class)->make();
$department->company()->associate($company);
$department->create();

Я получаю следующую ошибку: Integrity constraint violation: 19 NOT NULL constraint failed: companies.user_id (SQL: insert into "companies" ("updated_at", "created_at") values (2020-03-10 07:27:51, 2020-03-10 07:27:51))

Моя схема таблицы определена как this:

// users
Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('phone');
    $table->integer('user_type');
    $table->string('password');
    $table->rememberToken();
    $table->timestamps();
});

// companies
Schema::create('companies', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained()->onDelete('cascade');
    $table->string('name');
    $table->string('contact_email');
    $table->string('contact_phone');
    $table->timestamps();
});

// departments
Schema::create('departments', function (Blueprint $table) {
    $table->id();
    $table->foreignId('company_id')->constrained()->onDelete('cascade');
    $table->string('name');
    $table->string('contact_email');
    $table->string('contact_phone');
    $table->timestamps();
});

Насколько я понимаю, в таблицах SQL не должно быть NULL-значений, поэтому я намеренно стараюсь избегать ->nullable() в моих миграциях. Специально для таких внешних ключей.

РЕДАКТИРОВАТЬ:

Я попытался сделать это таким образом, я также сделал сводную таблицу для users_companies. Теперь я могу присоединить компанию, но я все еще получаю ошибку SQL при выполнении теста таким образом:

$user = factory(User::class)->create();
$company = factory(Company::class)->create();

$user->companies()->attach($company);
$company->departments()->create([
    'name' => 'Department 1',
    'contact_email' => 'department1@example.test',
    'contact_phone' => '123456789',
]);

Это также не выполняется с ошибкой, указанной ниже:

$company = factory(Company::class)->create();
$company->departments()->save(factory(Department::class)->make());

Ошибка заключается в следующем: Integrity constraint violation: 19 NOT NULL constraint failed: departments.company_id (SQL: insert into "departments" ("name", "contact_email", "contact_phone", "company_id", "updated_at", "created_at") values (Department 1, department1@example.test, '123456789', ?, 2020-03-11 07:59:31, 2020-03-11 07:59:31)).

CompanyFactory.php

<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\Company;
use Faker\Generator as Faker;

$factory->define(Company::class, function (Faker $faker) {
    return [
        'name' => 'Company 1',
        'contact_email' => 'company@example.test',
        'contact_phone' => '123456789',
    ];
});

Заводы

DepartmentFactory.php

<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\Department;
use Faker\Generator as Faker;

$factory->define(Department::class, function (Faker $faker) {
    return [
        'name' => 'Department 1',
        'contact_email' => 'department1@example.test',
        'contact_phone' => '123456789',
    ];
});

1 Ответ

2 голосов
/ 13 марта 2020

Некоторые проблемы с вашей структурой таблицы на первый взгляд очевидны.

  • Похоже, вы пытаетесь добавить столбец user_id в таблицу companies. Это не очень хорошая идея, если в вашей компании более одного сотрудника.
  • Если вы хотите использовать NOT NULL столбцы, вам лучше определить значение по умолчанию для каждого из них. .

Итак, мы можем начать с написания миграций примерно так, включая сводные таблицы для отношений компания / пользователь и отдел / пользователь:

// companies
Schema::create('companies', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('contact_email')->default('');
    $table->string('contact_phone')->default('');
    $table->timestamps();
});

// departments
Schema::create('departments', function (Blueprint $table) {
    $table->id();
    $table->foreignId('company_id')->constrained()->onDelete('cascade');
    $table->string('name');
    $table->string('contact_email')->default('');
    $table->string('contact_phone')->default('');
    $table->timestamps();
});

// users
Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('name')->default('');
    $table->string('phone')->default('');
    $table->integer('user_type')->default(0);
    $table->string('password');
    $table->rememberToken();
    $table->timestamps();
});

Schema::create('company_user', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained()->onDelete('cascade');
    $table->foreignId('company_id')->constrained()->onDelete('cascade');
});

Schema::create('department_user', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained()->onDelete('cascade');
    $table->foreignId('department_id')->constrained()->onDelete('cascade');
});

Теперь у нас есть ссылки между столы. Отдел является частью компании; пользователь может быть частью нескольких отделов и / или нескольких компаний. Это приводит к следующим отношениям :

class User extends Model {
    // many-to-many
    public function companies() {
        return $this->belongsToMany(App\Company::class);
    }
    // many-to-many
    public function departments() {
        return $this->belongsToMany(App\Department::class);
    }
}

class Company extends Model {
    public function departments() {
        // one-to-many
        return $this->hasMany(App\Department::class);
    }
    public function users() {
        // many-to-many
        return $this->belongsToMany(App\User::class);
    }
}

class Department extends Model {
    public function company() {
        // one-to-many (inverse)
        return $this->belongsTo(App\Company::class);
    }
    public function users() {
        // many-to-many
        return $this->belongsToMany(App\User::class);
    }
}

Теперь такой код должен работать:

$user = factory(User::class)->create();
$company = factory(Company::class)->create();

$user->companies()->attach($company);
$company->departments()->create([
    'name' => 'Department 1',
    'contact_email' => 'department1@example.test',
    'contact_phone' => '123456789',
]);

В частности, метод attach используется для обновления многих -ко-многим отношениям, которые вы, по-видимому, не определили, основываясь на исходной компоновке таблицы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...