การย้ายข้อมูล: ไม่สามารถเพิ่มข้อ จำกัด กุญแจต่างประเทศ


207

ฉันพยายามที่จะสร้างกุญแจต่างประเทศใน 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');
}

ความคิดใด ๆ เกี่ยวกับสิ่งที่ฉันทำผิดฉันต้องการทำให้ถูกต้องในขณะนี้เนื่องจากฉันมีตารางจำนวนมากที่ฉันต้องสร้างเช่นผู้ใช้ลูกค้าโครงการงานสถานะสถานะลำดับความสำคัญประเภททีม เป็นการดีที่ฉันต้องการสร้างตารางที่เก็บข้อมูลนี้ด้วยคีย์ต่างประเทศ, i .. e clients_projectและproject_tasksอื่น ๆ

หวังว่าใครบางคนสามารถช่วยฉันในการเริ่มต้น

คำตอบ:


356

เพิ่มในสองขั้นตอนและเป็นการดีที่จะทำให้มันไม่ได้ลงนามด้วย:

public function up()
{
    Schema::create('priorities', function($table) {
        $table->increments('id', true);
        $table->integer('user_id')->unsigned();
        $table->string('priority_name');
        $table->smallInteger('rank');
        $table->text('class');
        $table->timestamps('timecreated');
    });

   Schema::table('priorities', function($table) {
       $table->foreign('user_id')->references('id')->on('users');
   });

}

117
ขอบคุณอันโตนิโอ! สำหรับฉันปัญหาไม่ได้เพิ่ม unsigned () ในคอลัมน์ user_id เพื่อให้ตรงกับชนิดข้อมูลของคอลัมน์ id ในตารางผู้ใช้ ฟังก์ชันการเพิ่มขึ้นของ Laravel ('id') จะสร้างเลขจำนวนเต็มที่ไม่ได้ลงชื่อดังนั้นคอลัมน์ foreign key จะต้องไม่ได้ลงนาม
แบรดกริฟฟิ ธ

7
การเพิ่มที่ไม่ได้ลงชื่อนอกเหนือจากการแยกไปยังSchema::tableวิธีการช่วย! ขอบคุณ!
patrickjason91

4
สำหรับฉันมันไม่ได้ทำให้รหัสไม่ได้ลงนามเช่นกัน ขอบคุณสำหรับทิป.
Carl Weis

6
วิธีการแก้ปัญหาอยู่ในความคิดเห็นของ @BradGriffith ดังที่กล่าวไว้ข้างต้นฉันไม่จำเป็นต้องแยกจากกันเลย อาจดีกว่าที่จะอัปเดตคำตอบตาม
Matanya

11
ใช้$table->unsignedBigInteger('user_id')ถ้า user.id ของคุณคือbigIncrements
Maksim Ivanov

114

ตอบคำถามแล้ว แต่หวังว่าจะช่วยคนอื่นได้

ข้อผิดพลาดนี้เกิดขึ้นกับฉันเพราะฉันสร้างตารางการย้ายข้อมูลโดยมีรหัสต่างประเทศอยู่ก่อนก่อนที่จะมีรหัสหลักเป็นรหัสหลักในตารางเดิม migrate:makeการย้ายข้อมูลได้รับการดำเนินการในลำดับที่พวกเขาถูกสร้างขึ้นตามที่ระบุโดยชื่อไฟล์ที่สร้างขึ้นหลังจากการทำงาน เช่น2014_05_10_165709_create_student_table.phpเช่น

วิธีแก้ไขคือเปลี่ยนชื่อไฟล์ด้วย foreign key เป็นครั้งก่อนกว่าไฟล์ที่มีคีย์หลักตามที่แนะนำที่นี่: http://forumsarchive.laravel.io/viewtopic.php?id=10246

ฉันคิดว่าฉันต้องเพิ่ม $table->engine = 'InnoDB';


4
หลังจากที่คุณเปลี่ยนชื่อไฟล์การโยกย้ายและได้รับข้อผิดพลาดเช่น: ไม่สามารถเปิดสตรีม: ไม่มีไฟล์หรือไดเรกทอรีดังกล่าว (และชื่อการโยกย้ายเก่าจะปรากฏขึ้น) คุณต้องเรียกใช้: composer dump-autoload
Stelian

14
$ table-> engine = 'InnoDB'; จำเป็นต้องมีการบังคับใช้ foreign key ที่ระดับ MySql เอ็นจิ้น laravel เริ่มต้นคือ MyIsam ซึ่งไม่รองรับคีย์ต่างประเทศ!
François Breton

2
ขอบคุณสำหรับสิ่งนี้เช่นกัน แต่มันแปลกสำหรับฉันที่ใช้วิธีนี้ ฉันหมายความว่ามันสมเหตุสมผล แต่ควรมีวิธีการระบุลำดับของการดำเนินการย้ายข้อมูลอื่นนอกเหนือจากการเปลี่ยนชื่อไฟล์ด้วยตนเองและมาพร้อมกับวันที่ปลอมในกระบวนการ
allisius

2
ฉันมาที่นี่ไม่ใช่เพราะฉันได้รับข้อผิดพลาด แต่ฉันสามารถเพิ่มค่าที่ไม่ถูกต้องในคอลัมน์ซึ่งเป็นคีย์ต่างประเทศ จากนั้นฉันก็เห็นความคิดเห็นและตอบเกี่ยวกับ InnoDB นี่เป็นเรื่องดีที่จะรู้ ขอบคุณพวกคุณ :)
SuperNOVA

2
ลำดับที่คุณสร้างการย้ายข้อมูลของคุณยังคงมีความสำคัญเมื่อทำการย้ายข้อมูล ฉันพบปัญหานี้ แต่ได้แก้ไขปัญหาแล้ว
mugabits

60

Laravel ^ 5.8

ในฐานะของ Laravel 5.8สตับการย้ายข้อมูลใช้วิธี bigIncrements ในคอลัมน์ ID โดยค่าเริ่มต้น ก่อนหน้านี้คอลัมน์ ID ถูกสร้างขึ้นโดยใช้วิธีการเพิ่ม

สิ่งนี้จะไม่ส่งผลกระทบต่อรหัสที่มีอยู่ในโครงการของคุณ แต่ทราบว่าคอลัมน์ต่างประเทศที่สำคัญจะต้องเป็นชนิดเดียวกัน ดังนั้นคอลัมน์ที่สร้างขึ้นโดยใช้วิธีการเพิ่มขึ้นไม่สามารถอ้างอิงคอลัมน์ที่สร้างขึ้นโดยใช้วิธีการ bigIncrements

ที่มา: Migrations & bigIncrements


ตัวอย่าง

ลองจินตนาการว่าคุณกำลังสร้างแอพลิเคชันตามบทบาทที่เรียบง่ายและคุณจำเป็นต้องอ้างอิงuser_idในPIVOTตาราง"role_user"

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');
    });
}

ดังที่คุณเห็นบรรทัดความคิดเห็นจะส่งข้อยกเว้นแบบสอบถามเนื่องจากดังที่กล่าวไว้ในบันทึกย่อการอัพเกรดคอลัมน์คีย์ต่างประเทศจะต้องเป็นประเภทเดียวกันดังนั้นคุณต้องเปลี่ยนคีย์ foreing (ในตัวอย่างนี้คือuser_id ) เป็นbigIntegerในตารางrole_userหรือเปลี่ยนวิธีbigIncrements เป็นวิธีเพิ่มขึ้นในตารางผู้ใช้และใช้บรรทัดที่มีความคิดเห็นในตารางสาระสำคัญมันขึ้นอยู่กับคุณ


ฉันหวังว่าฉันจะสามารถชี้แจงปัญหานี้กับคุณ


1
ขอบคุณ. คุณช่วยชีวิตฉัน. ตามคำอธิบายของคุณฉันเปลี่ยนรหัสต่างประเทศเป็น bigInteger ตามที่คุณแนะนำ Schema::table('goal_objective', function (Blueprint $table) { $table->bigInteger('job_title_id')->after('target')->unsigned()->nullable(); $table->foreign('job_title_id')->references('id')->on('job_titles')->onDelete('set null'); } มันได้ผล ขอบคุณ.
Bruce Tong

1
@ BruceTong ฉันดีใจที่ฉันสามารถช่วยได้
chebaby

1
ใช่นี่คือคำตอบที่เกี่ยวข้องมากที่สุด
Mohd Abdul Mujib

1
คำตอบนี้มีประโยชน์มาก
Karim Pazoki

1
คำตอบที่ดีที่สุด ขอบคุณ
VishalParkash

49

ในกรณีของฉันปัญหาคือตารางหลักมีบันทึกอยู่แล้วและฉันบังคับให้คอลัมน์ใหม่ไม่เป็น NULL ดังนั้นการเพิ่ม -> nullable () ในคอลัมน์ใหม่จึงเป็นการหลอกลวง ในตัวอย่างของคำถามจะเป็นดังนี้:

$table->integer('user_id')->unsigned()->nullable();

หรือ:

$table->unsignedInteger('user_id')->nullable();

หวังว่านี่จะช่วยใครซักคน!


โปรดทราบว่าคอลัมน์ 'id' ในตารางหลักของคุณจะต้องมีการลงนาม! ใช้บรรทัดเช่น $ table-> increments ('id'); จะเริ่มต้นโดยอัตโนมัติเพื่อไม่ได้ลงนาม
Colin Stadig

สิ่งนี้ใช้ได้สำหรับฉัน ฉันเปลี่ยนชนิดข้อมูลของตารางหลักจาก BigIncrements เป็นการเพิ่มขึ้น
Emmanuel Benson

22

ในกรณีของฉันปัญหาusersคือการตั้งค่าการโยกย้ายที่สร้างขึ้นโดยอัตโนมัติสำหรับตาราง

...
$table->bigIncrements('id');
...

ดังนั้นฉันต้องเปลี่ยนประเภทคอลัมน์


$table->bigInteger('id');

เพื่อทำให้การโยกย้ายของฉันกับ foreign key ทำงานได้

สิ่งนี้มี laravel 5.8.2


เนื่องจากคอลัมน์คีย์ต่างประเทศต้องมีคอลัมน์ประเภทเดียวกันจึงหมายถึง
Daniele

9
สิ่งนี้ใช้ได้กับฉัน $ table-> unsignedBigInteger ('user_id'); ใน laravel 5.8. *
Adam Winnipass

ฉันยังมีปัญหากับ 5.8 นี้แก้ไขได้สำหรับฉัน! ขอบคุณ!
Mike Sheward

ช่วยฉันจากคืนที่ยาวนาน!
chq

19

ในกรณีของฉันปัญหาเกี่ยวกับเวลาในการย้ายข้อมูลจะต้องระมัดระวังในขณะที่สร้างการย้ายข้อมูลก่อนอื่นให้สร้างการย้ายเด็กที่ไม่ใช่การย้ายฐาน เพราะถ้าคุณสร้างการย้ายฐานก่อนซึ่งมีรหัสต่างประเทศของคุณจะมองหาตารางลูกและจะไม่มีตารางที่จะโยนข้อยกเว้น

เพิ่มเติมได้ที่:

เมื่อคุณสร้างการย้ายข้อมูลจะมีการประทับเวลาในตอนต้น สมมติว่าคุณได้สร้างแมวการโยกย้ายแล้วมันจะมีหน้าตา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 ช่างโยกย้าย มันจะโยนข้อยกเว้นเพราะการโยกย้ายครั้งแรกจะสร้างตารางฐานในฐานข้อมูลของคุณเพราะคุณได้สร้างการโยกย้ายนี้ก่อนและตารางฐานของเรามีข้อ จำกัด ที่สำคัญต่างประเทศซึ่งจะมองหาตารางลูกและตารางเด็กไม่อยู่ซึ่งอาจ ข้อยกเว้น..

ดังนั้น:

สร้างการย้ายข้อมูลตารางลูกก่อน

สร้างการโยกย้ายตารางฐานหลังจากการโยกย้ายลูกถูกสร้างขึ้น

PHP ช่างโยกย้าย

ทำมันจะทำงาน


13

ในกรณีของฉันฉันเพิ่งเปลี่ยนการโยกย้ายคำสั่งจะดำเนินการด้วยตนเองเพื่อสร้างผู้ใช้ตารางก่อน

ในฐานข้อมูลโฟลเดอร์ / การย้ายข้อมูล / ชื่อไฟล์การย้ายข้อมูลของคุณมีรูปแบบนี้: year_month_day_hhmmss_create_XXXX__table.php

เพียงเปลี่ยนชื่อสร้างไฟล์ผู้ใช้ดังนั้นวันที่สร้างตารางลำดับความสำคัญของตารางจะถูกตั้งค่าภายหลังวันที่ผู้ใช้ (แม้แต่หนึ่งวินาทีต่อมาก็เพียงพอแล้ว)


13

ใน laravel 5.8, users_table ใช้bigIncrements('id')ชนิดข้อมูลสำหรับคีย์หลัก ดังนั้นเมื่อคุณต้องการอ้างถึงข้อ จำกัด กุญแจต่างประเทศuser_idคอลัมน์ของคุณจะต้องunsignedBigInteger('user_id')พิมพ์


ขอบคุณมากฉันใช้เวลาหนึ่งชั่วโมงเพื่อหาสาเหตุว่าทำไมคีย์ต่างประเทศจึงทำให้เกิดข้อยกเว้น
Ya Basha

10

ฉันมีปัญหาเดียวกันกับการใช้Laravel 5.8 หลังจากดูเอกสาร laravel ให้ละเอียดยิ่งขึ้นที่นี่การย้ายข้อมูลและการวางแผนขนาดใหญ่ วิธีที่ฉันจะแก้ไขมันเป็นโดยการเพิ่มคีย์หลัก"$ 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']);
        });

9

ฉันมีปัญหากับ laravel 5.8 และฉันแก้ไขรหัสนี้ตามที่แสดงในเอกสารประกอบของ Laravelเพื่อที่ฉันจะเพิ่มรหัสต่างประเทศ

$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');

จากนั้นฉันก็วิ่ง $ php artisan migrate:refresh

เนื่องจากวากยสัมพันธ์นี้ค่อนข้างละเอียด Laravel จึงมีวิธีเพิ่มเติม terser ที่ใช้การประชุมเพื่อมอบประสบการณ์การพัฒนาที่ดีขึ้น ตัวอย่างด้านบนสามารถเขียนได้เช่น:

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

7

การใช้ Laravel 5.3 มีปัญหาเดียวกัน

การแก้ปัญหาคือการใช้unsignedIntegerแทนจำนวนเต็ม ( 'ชื่อ') -> ไม่ได้ลงนาม ()

ดังนั้นนี่คือสิ่งที่ทำงาน

$table->unsignedInt('column_name');
$table->foreign('column_name')->references('id')->on('table_name');

เหตุผลที่ใช้งานได้คือความจริงที่ว่าเมื่อใช้จำนวนเต็ม ('ชื่อ') ->คอลัมน์ที่สร้างในตารางมีความยาว 11 แต่เมื่อใช้unsigedInteger ('ชื่อ')คอลัมน์จะมีความยาว 10

ความยาว 10 คือความยาวของคีย์หลักเมื่อใช้ Laravel ดังนั้นความยาวคอลัมน์จึงตรงกัน


ชายขอบคุณสำหรับสิ่งที่ฉันกำลังจะยอมแพ้และเรียกใช้ sql ดิบในขณะที่ฉันเพิ่งพบโพสต์ของคุณ ฉันจะต้องอ่านเพิ่มเติมเกี่ยวกับสาเหตุที่คีย์หลัก laravel ถูกบังคับให้มีความยาว 10 และหากมีเหตุผลว่าทำไมการทำจำนวนเต็ม ('คอลัมน์') -> ไม่ได้ลงนาม () ควรแตกต่างจาก unsigedInteger ('คอลัมน์')
Arnaud Bouchot

6

ข้อผิดพลาดนี้เกิดขึ้นกับฉันเพราะ - ในขณะที่ตารางที่ฉันพยายามสร้างคือ InnoDB - ตารางต่างประเทศที่ฉันพยายามจะเชื่อมโยงให้เป็นตาราง MyISAM!


MyISAM ไม่สนับสนุนข้อ จำกัด กุญแจต่างประเทศ อาจเป็นไปได้เพราะการเปลี่ยนเป็น MyISAM ทำให้ไม่สนใจคีย์ต่างประเทศซึ่งอาจมีเหตุผล ระวัง.
greggle138

5

เราไม่สามารถเพิ่มความสัมพันธ์ได้เว้นแต่ว่าจะสร้างตารางที่เกี่ยวข้อง Laravel เรียกใช้การย้ายข้อมูลเรียงตามวันที่ของไฟล์การโยกย้าย ดังนั้นหากคุณต้องการสร้างความสัมพันธ์กับตารางที่มีอยู่ในไฟล์การโยกย้ายครั้งที่ 2 มันจะล้มเหลว

ฉันประสบปัญหาเดียวกันดังนั้นฉันจึงสร้างไฟล์การย้ายข้อมูลอีกหนึ่งไฟล์ในที่สุดเพื่อระบุความสัมพันธ์ทั้งหมด

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');
    });

1
คุณตั้งชื่อไฟล์อะไร 9999_99_99_999999_create_foreign_keys.php?
Iannazzi

การเพิ่ม 9999_99_99_99999 ไปยังชื่อไฟล์การย้ายข้อมูลเป็นความคิดที่ไม่ดีเนื่องจากจะทำให้ฟีเจอร์ย้อนกลับ
Maulik Gangani

5

ระวัง: เมื่อ Laravel ติดตั้งตารางโดยใช้

$table->increments('id');

ซึ่งเป็นมาตรฐานในการโยกย้ายส่วนใหญ่นี้จะตั้งค่าฟิลด์จำนวนเต็มไม่ได้ลงนาม ดังนั้นเมื่อทำการอ้างอิงจากต่างประเทศจากตารางอื่นไปยังฟิลด์นี้ตรวจสอบให้แน่ใจว่าในตารางอ้างอิงคุณตั้งค่าฟิลด์เป็น UnsignedInteger และไม่ใช่ (สิ่งที่ฉันคิดว่าเป็นฟิลด์) 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');
}

5

คุณควรเขียนด้วยวิธีนี้

public function up()
{
    Schema::create('transactions', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->float('amount', 11, 2);
        $table->enum('transaction type', ['debit', 'credit']);
        $table->bigInteger('customer_id')->unsigned();      
        $table->timestamps();                 
    });

    Schema::table('transactions', function($table) {
        $table->foreign('customer_id')
              ->references('id')->on('customers')
              ->onDelete('cascade');
    });     
}

ฟิลด์คีย์ต่างประเทศไม่ควรลงนามหวังว่าจะช่วยได้ !!


ไม่ใช่แค่ไม่ได้ลงนาม แต่เมื่อมันอ้างอิงคอลัมน์ bigIncrements มันควรจะ unsigedBigInteger
gondwe

4

สำหรับการเพิ่มข้อ จำกัด ของ foreign key ใน laravel ต่อไปนี้ใช้งานได้สำหรับฉัน:

  1. สร้างคอลัมน์ให้เป็น foreign key ดังต่อไปนี้:

    $ table-> จำนวนเต็ม ( 'column_name') -> ไม่ได้ลงนาม ();
  2. การเพิ่มบรรทัดข้อ จำกัด ทันทีหลังจาก (1) เช่น

    $ table-> จำนวนเต็ม ( 'column_name') -> ไม่ได้ลงนาม ();
    $ table-> ต่างประเทศ ( 'column_name') -> การอ้างอิง ( 'pk_of_other_table') -> บน ( 'other_table');

3

ฉันรู้ว่าเป็นคำถามเก่า แต่ให้แน่ใจว่าคุณกำลังทำงานกับการอ้างอิงเครื่องมือสนับสนุนที่เหมาะสมมีการกำหนด ตั้งเครื่องยนต์ innodb สำหรับทั้งตารางและชนิดข้อมูลเดียวกันสำหรับคอลัมน์อ้างอิง

$table->engine = 'InnoDB';

2

เมื่อไม่นานมานี้หลังจากถามคำถามเดิมโดยใช้ laravel 5.1 ฉันมีข้อผิดพลาดเหมือนกับการย้ายข้อมูลของฉันคือคอมพิวเตอร์ที่สร้างด้วยรหัสวันที่เดียวกันทั้งหมด ฉันไปตามแนวทางที่เสนอทั้งหมดจากนั้นทำการ refactored เพื่อค้นหาแหล่งที่มาของข้อผิดพลาด

ใน laracasts ที่ติดตามและในการอ่านโพสต์เหล่านี้ฉันเชื่อว่าคำตอบที่ถูกต้องนั้นคล้ายกับคำตอบของ Vickies โดยมีข้อยกเว้นที่คุณไม่จำเป็นต้องเพิ่มการเรียก schema แยกต่างหาก คุณไม่จำเป็นต้องตั้งค่าตารางเป็น 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_99_99_999999_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');
//        });

2

ง่ายมาก !!!

หากคุณสร้าง'priorities'ไฟล์การย้ายข้อมูลครั้งแรก Laravel จะรันครั้งแรก'priorities'ในขณะที่'users'ไม่มีตารางอยู่

วิธีเพิ่มความสัมพันธ์กับตารางที่ไม่มีอยู่!

การแก้ไข: ดึง รหัสต่างประเทศออกจาก 'priorities'ตาราง ไฟล์การโยกย้ายของคุณควรเป็นเช่นนี้:

ป้อนคำอธิบายรูปภาพที่นี่

และเพิ่มลงในไฟล์การย้ายข้อมูลใหม่ชื่อของที่นี่คือcreate_prioritiesForeignKey_tableและเพิ่มรหัสเหล่านี้:

public function up()
{        
    Schema::table('priorities', function (Blueprint $table) {          
        $table->foreign('user_id')
              ->references('id')
              ->on('users');                        
    });
}

2

ตรวจสอบให้แน่ใจว่าคอลัมน์ foreing ของคุณอยู่เหนือความโกรธกว้างของการคีย์คอลัมน์ล่วงหน้า

ฉันหมายถึง foreingkey ของคุณ (ในตารางที่สอง) จะต้องเป็นชนิดเดียวกันกับของรหัส ponter pricipal ของคุณ (ในตารางแรก)

คีย์หลักของตัวชี้ของคุณจะต้องเพิ่มวิธีที่ไม่ได้ลงชื่อให้ฉันแสดง:

บนตารางการโยกย้ายครั้งแรกของคุณ:

$table->increments('column_name'); //is INTEGER and UNSIGNED

บนตารางการโยกย้าย SECOND ของคุณ:

$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

บนตารางการโยกย้าย SECOND ของคุณ:

$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');

ดูประเภทตัวเลขช่วงตัวเลข


2

สิ่งหนึ่งที่ฉันสังเกตคือถ้าตารางใช้เอ็นจินต่างจากข้อ จำกัด ของรหัสต่างประเทศไม่ทำงาน

ตัวอย่างเช่นหากหนึ่งตารางใช้:

$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
    });
}

1

ในกรณีของฉันฉันถูกอ้างอิงจำนวนเต็ม idคอลัมน์ในสตริง user_idคอลัมน์ ฉันเปลี่ยน:

$table->string('user_id')

ถึง:

$table->integer('user_id')->unsigned();

หวังว่ามันจะช่วยให้ใครบางคน!


1

ส่วนสำคัญคือวิธีการที่ต่างประเทศใช้ALTER_TABLEในการสร้างเขตข้อมูลที่มีอยู่แล้วเป็นคีย์ต่างประเทศ ดังนั้นคุณต้องกำหนดประเภทของตารางก่อนที่จะใช้รหัสที่ต่างประเทศ อย่างไรก็ตามไม่จำเป็นต้องอยู่ในSchema::สายที่แยกจากกัน คุณสามารถทำได้ทั้งในการสร้างเช่นนี้:

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ถูกตั้งค่าเป็นไม่ได้ลงชื่อเพื่อจับคู่คีย์ต่างประเทศ


1

คุณสามารถส่งผ่านพารามิเตอร์บูลีนโดยตรงในคอลัมน์จำนวนเต็มโดยบอกว่าควรไม่ได้ลงนามหรือไม่ ใน laravel 5.4 รหัสต่อไปนี้แก้ไขปัญหาของฉัน

        $table->integer('user_id', false, true);

นี่คือพารามิเตอร์ที่สองเท็จแสดงว่าไม่ควรเพิ่มโดยอัตโนมัติและพารามิเตอร์ที่สามจริงแสดงว่าควรไม่ได้ลงนาม คุณสามารถเก็บข้อ จำกัด foreign key ไว้ในการย้ายข้อมูลเดียวกันหรือแยกกัน มันทำงานได้ทั้ง


1

หากวิธีการแก้ปัญหาด้านบนไม่ทำงานสำหรับมือใหม่ตรวจสอบว่า ID ทั้งสองมีประเภทเดียวกัน: ทั้งคู่integerหรือทั้งสองอย่างคือbigInteger... คุณสามารถมีสิ่งนี้:

ตารางหลัก (ตัวอย่างผู้ใช้)

$table->bigIncrements('id');

ตารางลูก (ลำดับความสำคัญตัวอย่าง)

$table->unsignedInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');

แบบสอบถามนี้จะล้มเหลวเนื่องจากusers.idเป็นBIG INTEGERในขณะที่เป็นpriorities.user_idINTEGER

แบบสอบถามที่ถูกต้องในกรณีนี้จะเป็นดังนี้:

$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');

1

ในกรณีของฉันมันไม่ทำงานจนกว่าฉันจะรันคำสั่ง

composer dump-autoload

ด้วยวิธีนี้คุณสามารถปล่อยคีย์ต่างประเทศไว้ในสคีมาของการสร้าง

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');
}

1

นอกจากนี้ยังอาจเป็นลำดับของการโยกย้ายการสร้างของคุณ หากคุณสร้างตารางลำดับความสำคัญเป็นอันดับแรกและหลังจากตารางผู้ใช้งานแล้วจะเกิดความผิดพลาด เนื่องจากการโยกย้ายครั้งแรกมองหาตารางผู้ใช้ ดังนั้นคุณต้องเปลี่ยนลำดับของการย้ายข้อมูล

app/database/migrations

ไดเรกทอรี


1

สำหรับฉันคอลัมน์ตารางที่ตารางลูกของฉันอ้างอิงไม่ได้จัดทำดัชนี

Schema::create('schools', function (Blueprint $table) {
    $table->integer('dcid')->index()->unque();
    $table->integer('school_number')->index(); // The important thing is that this is indexed
    $table->string('name');
    $table->string('abbreviation');
    $table->integer('high_grade');
    $table->integer('low_grade');
    $table->timestamps();
    $table->primary('dcid');
});

Schema::create('students', function (Blueprint $table) {
      $table->increments('id');
      $table->integer('dcid')->index()->unique()->nullable();
      $table->unsignedInteger('student_number')->nullable();
      $table->integer('schoolid')->nullable();
      $table->foreign('schoolid')->references('school_number')->on('schools')->onDelete('set null');
      // ...
});

ไม่สนใจการตั้งชื่อที่น่ากลัวมันมาจากระบบอื่นที่ออกแบบมาอย่างน่ากลัว


1

บางครั้งข้อผิดพลาดนี้อาจเกิดขึ้นเนื่องจากลำดับของการย้ายข้อมูล

Like Users และ Order เป็นสองตาราง

ตารางการสั่งซื้อมีคีย์ foriegn ของผู้ใช้ (ในระหว่างการโยกย้ายหากการสั่งซื้อการโยกย้ายครั้งแรกแล้วมันจะทำให้เกิดปัญหาเพราะไม่มีผู้ใช้เพื่อให้ตรงกับกุญแจต่างประเทศ)

การแก้ไข: เพียงแค่ใส่ตารางอัพเดตคำสั่งซื้อของคุณภายใต้ผู้ใช้สำหรับการปรับปรุง

ตัวอย่าง: ในกรณีของฉันตารางการศึกษาและมหาวิทยาลัยตารางการศึกษา

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');
    });

0

สิ่งหนึ่งที่ฉันคิดว่าหายไปจากคำตอบที่นี่และโปรดแก้ไขให้ฉันถ้าฉันผิด แต่คีย์ต่างประเทศจะต้องได้รับการจัดทำดัชนีในตารางเดือย อย่างน้อยใน mysql ที่ดูเหมือนจะเป็นกรณี

public function up()
{
    Schema::create('image_post', function (Blueprint $table) {
        $table->engine = 'InnoDB';
        $table->increments('id');
        $table->integer('image_id')->unsigned()->index();
        $table->integer('post_id')->unsigned()->index();
        $table->timestamps();
    });

    Schema::table('image_post', function($table) {
        $table->foreign('image_id')->references('id')->on('image')->onDelete('cascade');
        $table->foreign('post_id')->references('id')->on('post')->onDelete('cascade');
    });

}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.