我试图在Laravel中创建外键,但是当我使用artisan迁移我的表时,我抛出了以下错误:
[Illuminate\Database\QueryException]
SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint (SQL
: alter table `priorities` add constraint priorities_user_id_foreign foreign
key (`user_id`) references `users` (`id`))
我的迁移代码如下:
优先级迁移文件
public function up()
{
//
Schema::create('priorities', function($table) {
$table->increments('id', true);
$table->integer('user_id');
$table->foreign('user_id')->references('id')->on('users');
$table->string('priority_name');
$table->smallInteger('rank');
$table->text('class');
$table->timestamps('timecreated');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
Schema::drop('priorities');
}
用户迁移文件
public function up()
{
//
Schema::table('users', function($table)
{
$table->create();
$table->increments('id');
$table->string('email');
$table->string('first_name');
$table->string('password');
$table->string('email_code');
$table->string('time_created');
$table->string('ip');
$table->string('confirmed');
$table->string('user_role');
$table->string('salt');
$table->string('last_login');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
Schemea::drop('users');
}
关于我做错了什么,我现在想要得到这个,因为我有很多表,我需要创建例如用户,客户端,项目,任务,状态,优先级,类型,团队。理想情况下,我想创建表持有这些数据与外键,即clients_project和project_tasks等。
希望有人能帮我开始。
在我的案例中,问题在于迁移时机,在创建迁移时要小心,首先创建子迁移,而不是基础迁移。因为如果你先创建base migration,有外键就会寻找子表,不会有抛出异常的表。
进一步:
当您创建迁移时,它的开头有一个时间戳。假设你已经创建了一个迁移猫,它看起来像2015_08_19_075954_the_cats_time.php,它有这样的代码
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class TheCatsTime extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('cat', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->date('date_of_birth');
$table->integer('breed_id')->unsigned()->nullable();
});
Schema::table('cat', function($table) {
$table->foreign('breed_id')->references('id')->on('breed');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('cat');
}
}
在创建基表之后,创建另一个迁移品种,即子表,它有自己的创建时间和日期戳。
代码如下所示:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class BreedTime extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('breed', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('breed');
}
}
看起来这两个表都是正确的,但当你运行PHP artisan迁移。它会抛出一个异常,因为迁移会首先在你的数据库中创建基表因为你先创建了这个迁移,我们的基表有外键约束,它会寻找子表,而子表不存在,这可能是一个异常。
So:
首先创建子表迁移。
在创建子迁移之后创建基表迁移。
PHP工匠迁移。
做就行了
我们不能添加关系,除非创建了相关的表。Laravel根据迁移文件的日期顺序运行迁移。因此,如果您想要与第二个迁移文件中存在的表创建关系,则会失败。
我也遇到了同样的问题,所以我最后创建了一个迁移文件来指定所有关系。
Schema::table('properties', function(Blueprint $table) {
$table->foreign('user')->references('id')->on('users')->onDelete('cascade');
$table->foreign('area')->references('id')->on('areas')->onDelete('cascade');
$table->foreign('city')->references('id')->on('cities')->onDelete('cascade');
$table->foreign('type')->references('id')->on('property_types')->onDelete('cascade');
});
Schema::table('areas', function(Blueprint $table) {
$table->foreign('city_id')->references('id')->on('cities')->onDelete('cascade');
});
在最初的问题之后的几年,我使用laravel 5.1,我有同样的错误,因为我的迁移是由计算机生成的,所有的日期代码都是相同的。我遍历了所有提出的解决方案,然后重构以找到错误源。
在遵循laracast和阅读这些文章时,我相信正确答案与Vickies的答案相似,除了您不需要添加单独的模式调用。你不需要设置Innodb,我假设laravel现在正在做这件事。
迁移只需要正确地计时,这意味着您将(稍后)修改需要外键的表的文件名中的日期代码。另外,对于不需要外键的表,降低数据码。
修改日期码的好处是您的迁移代码将更容易阅读和维护。
到目前为止,我的代码是通过调整时间代码来向后推需要外键的迁移。
但是我有几百个表,所以在最后,我有最后一个表用于外键。只是为了让事情顺利进行。我假设我将把它们拉到正确的文件中,并在测试时修改数据码。
例如:文件2016_01_18_999999_create_product_options_table。它需要创建产品表。看一下文件名。
public function up()
{
Schema::create('product_options', function (Blueprint $table) {
$table->increments('id');
$table->integer('product_attribute_id')->unsigned()->index();
$table->integer('product_id')->unsigned()->index();
$table->string('value', 40)->default('');
$table->timestamps();
//$table->foreign('product_id')->references('id')->on('products');
$table->foreign('product_attribute_id')->references('id')->on('product_attributes');
$table->foreign('product_id')->references('id')->on('products');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('product_options');
}
产品表:首先需要迁移这个表。2015年_01_18_000000_create_products_table
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->string('style_number', 64)->default('');
$table->string('title')->default('');
$table->text('overview')->nullable();
$table->text('description')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('products');
}
最后是我临时用来解决问题的文件,我将在为我命名为9999_99_9999_create_foreign_keys .php的模型编写测试时重构该文件。当我把这些键拉出来的时候,这些键就被注释了,但是你明白我的意思。
public function up()
{
// Schema::table('product_skus', function ($table) {
// $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
// });
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
// Schema::table('product_skus', function ($table)
// {
// $table->dropForeign('product_skus_product_id_foreign');
// });
其要点是,外部方法使用ALTER_TABLE将一个预先存在的字段转换为外键。所以在应用外键之前必须定义表类型。但是,它不必在单独的Schema::调用中。你可以在create中做这两件事,像这样:
public function up()
{
Schema::create('priorities', function($table) {
$table->increments('id', true);
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
$table->string('priority_name');
$table->smallInteger('rank');
$table->text('class');
$table->timestamps('timecreated');
});
}
还要注意,user_id的类型被设置为unsigned以匹配外键。
确保你的外分栏超过外分键栏的宽范围
我的意思是你的前键(在第二个表)必须是相同类型的你的ponter主键(在第一个表)
您的指针主键必须添加unsigned方法,让我显示:
在你的第一个迁移表上:
$table->increments('column_name'); //is INTEGER and UNSIGNED
在第二个迁移表上:
$table->integer('column_forein_name')->unsigned(); //this must be INTEGER and UNSIGNED
$table->foreign('column_forein_name')->references('column_name')->on('first_table_name');
另一个例子可以看出区别
在你的第一个迁移表上:
$table->mediumIncrements('column_name'); //is MEDIUM-INTEGER and UNSIGNED
在第二个迁移表上:
$table->mediumInteger('column_forein_name')->unsigned(); //this must be MEDIUM-INTEGER and UNSIGNED
$table->foreign('column_forein_name')->references('column_name')->on('first_table_name');
请参阅mysql数值类型表范围
如果以上解决方案都不适合新手,检查两个id是否具有相同的类型:都是整数或都是bigInteger,…你可以有这样的东西:
主表(例如用户)
$table->bigIncrements('id');
子表(例如优先级)
$table->unsignedInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
此查询将失败,因为用户。id是一个大整数,而优先级。user_id是一个整数。
在这种情况下,正确的查询如下:
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
注意:当Laravel设置一个表使用
$table->increments('id');
这在大多数迁移中是标准的,这将设置一个无符号整数字段。因此,当从另一个表对这个字段进行外部引用时,确保在引用表中,您将字段设置为UnsignedBigInteger,而不是(我假设是一个)UnsignedBigInteger字段。
例如:在迁移文件2018_12_12_123456_create_users_table.php中:
Schema::create('users', function (Blueprint $table){
$table->increments('id');
$table->string('name');
$table->timestamps();
然后在迁移文件2018_12_12_18000000_create_permissions_table.php中,该文件将外部引用设置回用户:
Schema::create('permissions', function (Blueprint $table){
$table->increments('id');
$table->UnsignedInteger('user_id'); // UnsignedInteger = "increments" in users table
$table->boolean('admin');
$table->boolean('enabled');
$table->timestamps();
// set up relationship
$table->foreign('user_id')->reference('id')->on('users')->onDelete('cascade');
}
我在使用Laravel 5.8时也遇到了同样的问题。在仔细研究laravel文档之后,还有Migrations & bigIncrements。我解决这个问题的方法是通过添加主键“$table->bigIncrements('id')”到与表“用户”及其关联相关的每一个表,在我的情况下,表“角色”。最后,我有“$table->unsignedBigInteger”用于将角色关联到用户(多对多),即表“role_user”。
1. Users table
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
2. Roles Table
Schema::create('roles', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name')->unique();
$table->string('display_name')->nullable();
$table->string('description')->nullable();
$table->timestamps();
});
3. Table role_user
Schema::create('role_user', function (Blueprint $table) {
$table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('role_id');
$table->foreign('user_id')->references('id')->on('users')
->onUpdate('cascade')->onDelete('cascade');
$table->foreign('role_id')->references('id')->on('roles')
->onUpdate('cascade')->onDelete('cascade');
$table->primary(['user_id', 'role_id']);
});
拉拉维尔 ^5.8
从Laravel 5.8开始,迁移存根在ID上使用bigIncrements方法
列。方法创建ID列
增量的方法。
这不会影响项目中的任何现有代码;然而,是
注意外键列必须具有相同的类型。因此,一个
使用increments方法创建的列不能引用列
使用bigIncrements方法创建。
来源:Migrations & bigIncrements
例子
假设您正在构建一个简单的基于角色的应用程序,并且需要在PIVOT表“role_user”中引用user_id。
2019年_05_05_112458_create_users_table.php
// ...
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('full_name');
$table->string('email');
$table->timestamps();
});
}
2019_05_05_120634_create_role_user_pivot_table.php
// ...
public function up()
{
Schema::create('role_user', function (Blueprint $table) {
// this line throw QueryException "SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint..."
// $table->integer('user_id')->unsigned()->index();
$table->bigInteger('user_id')->unsigned()->index(); // this is working
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
}
As you can see, the commented line will throw a query exception, because, as mentioned in the upgrade notes, foreign key columns must be of the same type, therefore you need to either change the foreing key (in this example it's user_id) to bigInteger in role_user table or change bigIncrements method to increments method in users table and use the commented line in the pivot table, it's up to you.
I hope i was able to clarify this issue to you.
我注意到的一件事是,如果表使用不同的引擎比外键约束不起作用。
例如,如果一个表使用:
$table->engine = 'InnoDB';
还有其他用途
$table->engine = 'MyISAM';
会产生一个错误:
SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint
你可以通过在表创建的最后添加InnoDB来解决这个问题,如下所示:
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('business_unit_id')->nullable();
$table->string('name', 100);
$table->foreign('business_unit_id')
->references('id')
->on('business_units')
->onDelete('cascade');
$table->timestamps();
$table->softDeletes();
$table->engine = 'InnoDB'; # <=== see this line
});
}
我在laravel 5.8有这个问题,我修复了这个代码,如laravel文档中所示,在我添加外键的地方。
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
然后我运行$ PHP artisan migrate:refresh
由于这种语法相当冗长,Laravel提供了额外的、更简洁的方法,使用约定来提供更好的开发体验。上面的例子可以这样写:
Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')->constrained()->onDelete('cascade');
});
有时这种错误可能是由于迁移的顺序造成的。
Users和Order是两个表
订单表有用户的外键
(在迁移过程中,如果Order表先迁移,则会导致问题,因为没有用户匹配外键)
解决方案:
只需将您的Order Update表放在用户下面进行更新
例子:
在我的例子中,教育和大学表
教育表
public function up()
{
Schema::create('doc_education', function (Blueprint $table) {
$table->increments('id');
$table->integer('uni_id')->unsigned()->nullable();
$table->timestamps();
});
}
在大学里
Schema::create('doc_universties', function (Blueprint $table) {
$table->increments('id');
$table->string('uni_name');
$table->string('location')->nullable();
$table->timestamps();
//
});
Schema::table('doc_education', function(Blueprint $table) {
$table->foreign('uni_id')->references('id')
->on('doc_universties')->onDelete('cascade');
});
快捷的解决方案:
/ /内部模式::创建
表- >外国(user_id) -先导入bigInteger (user_id) - > >无符号()- >索引();
/ /内部模式::表
$table->foreign('users_id')->references('id')->on('users')->onUpdate('cascade')->onDelete('cascade');
//正在编写代码。
public function up()
{
//
Schema::create('priorities', function($table) {
$table->increments('id', true);
$table->integer('user_id');
$table->foreign('user_id')->bigInteger('user_id')->unsigned()->index();
$table->string('priority_name');
$table->smallInteger('rank');
$table->text('class');
$table->timestamps('timecreated');
});
Schema::table('administrador', function($table) {
$table->foreign('users_id')->references('id')->on('users')
->onUpdate('cascade')
->onDelete('cascade');
;
});
}