在 laravel 5.2 中使用工厂关系违反完整性约束

Posted

技术标签:

【中文标题】在 laravel 5.2 中使用工厂关系违反完整性约束【英文标题】:Integrity constraint violation using factory relationships in laravel 5.2 【发布时间】:2016-07-18 08:41:51 【问题描述】:

我是 laravel 测试的新手,我正在尝试使用模型工厂创建虚拟数据。 我有三张桌子:

公司 客户 简介

一家公司有很多客户,一个客户有很多简报。 clientsbriefs 的格式非常相似。他们都有外键firm_idclient_id。 在进行 phpunit 测试时,我想使用以下代码创建来自公司的客户实例和来自客户的简报实例:

$client = $firm->clients()
               ->save(factory(App\SearchFirmClient::class)->create());
$brief  = $client->briefs()
                 ->save(factory(App\SearchFirmBrief::class)->create());

$client 的创建毫不费力,但 $brief 抛出错误:

Illuminate\Database\QueryException: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'client_id' cannot be null (SQL: insert into `search_firms_briefs` (`user_id`, `title`, `description`, `contact_id`, `client_id`, `updated_at`, `created_at`) values (1, Et in amet., Quo soluta ut impedit nesciunt autem. Laborum aperiam est non molestiae animi non quod. Explicabo eligendi doloribus ex quia vitae placeat ut., 0, , 2016-03-30 10:06:34, 2016-03-30 10:06:34))

两个表格的格式:

Schema::create('search_firms_clients', function(Blueprint $table)

    $table->increments('client_id');
    $table->integer('search_firm_id')->unsigned();
    $table->foreign('search_firm_id')->references('id')->on('search_firms')->onDelete('cascade');           
    $table->string('name');
    $table->softDeletes();
    $table->timestamps();
);

Schema::create('search_firms_briefs', function(Blueprint $table)

    $table->increments('brief_id');
    $table->integer('client_id')->unsigned();
    $table->foreign('client_id')->references('client_id')->on('search_firms_clients')->onDelete('cascade');         
    $table->string('title');
    $table->softDeletes();
    $table->timestamps();
);

每个模型工厂:

$factory->define(App\SearchFirmClient::class, function ($faker) 
    return [
        'name'      => $faker->company,
        'email'     => $faker->companyEmail,
        'phone'     => $faker->phoneNumber,
        'address'   => $faker->address,
        'website'   => $faker->url,
    ];
);

$factory->define(App\SearchFirmBrief::class, function ($faker) 
    return [
        'user_id'       => 1,
        'title'         => $faker->sentence(3),
        'description'   => $faker->text(),
        'contact_id'    => 0,
    ];
);

关系:

class SearchFirm extends Model


    protected $table = 'search_firms';
    protected $primaryKey = 'id';

    public function clients() 
        return $this->hasMany('SearchFirmClient', 'search_firm_id');
    


class SearchFirmClient extends Model


    use SoftDeletes;

    protected $table        = 'search_firms_clients';
    protected $primaryKey   = 'client_id';
    protected $dates        = [ 'deleted_at' ];


    public function briefs()
    
        return $this->hasMany('SearchFirmBrief', 'client_id')->orderBy( 'updated_at', 'desc');
    


class SearchFirmBrief extends Model


    use SoftDeletes;

    protected $table = 'search_firms_briefs';
    protected $primaryKey = 'brief_id';
    protected $touches = array('client');
    protected $dates = [ 'deleted_at'];

    public function client() 
        return $this->belongsTo('SearchFirmClient', 'client_id');
    

【问题讨论】:

【参考方案1】:

问题 #1

briefs 表上没有 id 列,但您在 clients 表上引用它。

把外键改成brief_id

Schema::create('search_firms_clients', function(Blueprint $table)

    $table->increments('client_id');
    $table->integer('search_firm_id')->unsigned();
    $table->foreign('search_firm_id')
          ->references('brief_id') // <-- Change this
          ->on('search_firms')
          ->onDelete('cascade');           
    $table->string('name');
    $table->softDeletes();
    $table->timestamps();
);

Schema::create('search_firms_briefs', function(Blueprint $table)

    $table->increments('brief_id');
    $table->integer('client_id')->unsigned();
    $table->foreign('client_id')->references('client_id')->on('search_firms_clients')->onDelete('cascade');         
    $table->string('title');
    $table->softDeletes();
    $table->timestamps();
);

问题 #2

您没有user_id 成员。

$factory->define(App\SearchFirmBrief::class, function ($faker) 
    return [
        'client_id'     => 1, // <-- change this
        'title'         => $faker->sentence(3),
        'description'   => $faker->text(),
        'contact_id'    => 0,
    ];
);

结论

最好遵循 Laravel 的命名标准,以后会省去很多麻烦(即使用默认表名,主键名)

【讨论】:

search_firms_clients 表引用了主键为'id'search_firm 表。 clients 模型创建完成,没问题。问题在于 briefs 模型引用了新创建的 clients 模型。 尝试运行artisan migrate:refresh 或手动删除数据库并重新迁移

以上是关于在 laravel 5.2 中使用工厂关系违反完整性约束的主要内容,如果未能解决你的问题,请参考以下文章

SQLSTATE[23000]:违反完整性约束:在 Laravel 5.2 中

使用 Laravel ORM 抽象保存新的不可为空的关系,而不会违反数据库完整性约束

Laravel 5.2:无法找到具有名称的工厂 [默认]

Laravel 删除(违反完整性约束)

laravel 8 播种,SQLSTATE[23000]:违反完整性约束:

Laravel 迁移 - 违反完整性约束:1452 无法添加或更新子行:外键约束失败