Migração: não é possível adicionar restrição de chave estrangeira

207

No entanto, estou tentando criar chaves estrangeiras no Laravel quando migro minha tabela usando artisano seguinte erro:

[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`))     

Meu código de migração é o seguinte:

arquivo de migração de prioridades

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

arquivo de migração de usuários

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

Qualquer idéia sobre o que fiz de errado, quero entender agora, pois tenho muitas tabelas que preciso criar, por exemplo: Usuários, Clientes, Projetos, Tarefas, Status, Prioridades, Tipos, Equipes. Idealmente, quero criar tabelas que armazenam esses dados com as chaves estrangeiras, i..e clients_projecte project_tasksetc.

Espero que alguém possa me ajudar a começar.

001221
fonte

Respostas:

357

Adicione-o em duas etapas, e é bom torná-lo sem sinal também:

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

}
Antonio Carlos Ribeiro
fonte
117
Obrigado Antonio! Para mim, o problema não foi adicionar unsigned () na coluna user_id, para que correspondesse ao tipo de dados da coluna id na tabela de usuários. A função de incrementos ('id') do Laravel cria um número inteiro sem sinal; portanto, a coluna da chave estrangeira também precisa ser sem sinal.
Brad Griffith
7
adicionar sem sinal, além de separar para o Schema::tablemétodo, ajudou! Obrigado!
precisa
4
Para mim, não estava deixando o ID sem assinatura também. Obrigado pela dica.
Carl Weis
6
A solução está no comentário de @BradGriffith. Como mencionado acima, não há necessidade de separar nada. Talvez seja melhor atualizar a resposta adequadamente.
Matanya
11
Use $table->unsignedBigInteger('user_id')se o seu user.id for #bigIncrements
Maksim Ivanov
114

Pergunta já respondida, mas espero que isso possa ajudar outra pessoa.

Este erro ocorreu para mim porque criei a tabela de migração com a chave estrangeira antes de a chave existir como chave primária na tabela original. As migrações são executadas na ordem em que foram criadas, conforme indicado pelo nome do arquivo gerado após a execução migrate:make. Por exemplo 2014_05_10_165709_create_student_table.php.

A solução foi renomear o arquivo com a chave estrangeira para um período anterior ao arquivo com a chave primária, conforme recomendado aqui: http://forumsarchive.laravel.io/viewtopic.php?id=10246

Eu acho que também tive que adicionar $table->engine = 'InnoDB';

haakym
fonte
4
Depois de renomear o arquivo de migração e obter alguns erros como: Falha ao fluxo aberto: Nenhum tal lima ou diretório (e o nome de migração de idade é exibido) você tem que correr: compositor despejo-autoload
Stelian
14
$ table-> engine = 'InnoDB'; é necessário para impor a chave estrangeira no nível do MySQL. O mecanismo laravel padrão é o MyIsam, que não suporta chaves estrangeiras!
François Breton
2
isso funcionou para mim também, obrigado. Mas me parece um pouco estranho que funcione dessa maneira. Quero dizer, faz sentido, mas deve haver uma maneira de especificar a ordem da execução da migração, além de renomear manualmente os arquivos e apresentar datas falsas no processo
allisius
2
Eu vim aqui não porque estava recebendo erros, mas consegui adicionar valores incorretos à coluna que era uma chave estrangeira. Então eu vi o comentário e a resposta sobre o InnoDB. Isso foi bom de saber. Obrigado pessoal :)
SuperNOVA
2
A ordem em que você criou suas migrações ainda permanece importante durante a migração. Corri para este problema, mas isso resolveu.
mugabits
60

Laravel ^ 5.8

No Laravel 5.8 , os stubs de migração usam o método bigIncrements nas colunas de ID por padrão. Anteriormente, as colunas de ID eram criadas usando o método incrementos.

Isso não afetará nenhum código existente no seu projeto; no entanto, esteja ciente de que as colunas de chave estrangeira devem ser do mesmo tipo . Portanto, uma coluna criada usando o método incrementos não pode fazer referência a uma coluna criada usando o método bigIncrements.

Fonte: Migrações e BigIncrements


Exemplo

Vamos imaginar que você esteja criando um aplicativo simples baseado em funções e precise fazer referência a user_id na tabela 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');
    });
}

Como você pode ver, a linha comentada gerará uma exceção de consulta, porque, como mencionado nas notas de atualização, as colunas de chave estrangeira devem ser do mesmo tipo ; portanto, você precisa alterar a chave de extração (neste exemplo, é user_id ) para bigInteger na tabela role_user ou altere o método bigIncrements para incrementos na tabela users e use a linha comentada na tabela dinâmica, é com você.


Espero poder esclarecer esta questão para você.

chebaby
fonte
1
Obrigado. você salvou minha vida. Após sua explicação, mudei minha chave estrangeira para bigInteger, como você sugeriu. 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'); } Funcionou. Obrigado.
Bruce Tong
1
@BruceTong, estou feliz por poder ajudar.
chebaby
1
Sim, esta é a resposta mais relevante.
Mohd Abdul Mujib
1
Esta resposta é muito útil.
Karim Pazoki 5/09/19
1
Melhor resposta. Obrigado
VishalParkash
49

No meu caso, o problema era que a tabela principal já tinha registros e eu estava forçando a nova coluna a não ser NULL. Então, adicionar um -> nullable () à nova coluna fez o truque. No exemplo da pergunta, seria algo como isto:

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

ou:

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

Espero que isso ajude alguém!

AdrianCR
fonte
Observe que a coluna 'id' na sua tabela pai também precisa estar sem sinal! Usando uma linha como $ table-> incrementos ('id'); será automaticamente padronizado como não assinado.
Colin Stadig
Isso funcionou para mim. Alterei o tipo de dados do ID da tabela pai de BigIncrements para incrementos.
Emmanuel Benson
22

No meu caso, o problema era que a migração gerada automaticamente para a userstabela estava configurando

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

Então eu tive que mudar o tipo de coluna


$table->bigInteger('id');

para fazer minha migração com a chave estrangeira funcionar.

Isso com laravel 5.8.2

Daniele
fonte
Uma vez que a coluna de chave externa devem ter o mesmo tipo de coluna refere-se a
Daniele
9
Isso funcionou para mim $ table-> unsignedBigInteger ('user_id'); em laravel 5,8 *.
Adam Winnipass
Eu também tive esse problema com 5.8, isso corrigiu para mim! Obrigado!
Mike Sheward
Me salvou de uma longa noite!
chq 14/05/19
19

No meu caso, o problema era que o tempo de migração tenha cuidado ao criar migrações, primeiro crie a migração filho do que a migração base. Porque se você criar a migração de base primeiro que tiver sua chave estrangeira, procurará tabela filho e não haverá tabela que, em seguida, lança uma exceção.

Além disso:

Quando você cria a migração, ela possui um registro de data e hora no início. digamos que você criou um gato de migração para que ele pareça 2015_08_19_075954_the_cats_time.phpe tenha esse código

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

E depois de criar a tabela base, você cria outra raça de migração, a tabela filha, que possui seu próprio horário de criação e data. O código será parecido com:

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

parece que ambas as tabelas estão corretas, mas quando você executa o php artisan migrate . Isso gerará uma exceção porque a migração criará primeiro a tabela base no seu banco de dados porque você criou essa migração primeiro e nossa tabela base possui restrição de chave estrangeira, que procurará a tabela filho e a tabela filho não existe, o que provavelmente é uma exceção..

Assim:

Crie a migração da tabela filho primeiro.

Crie a migração da tabela base após a criação da migração filho.

artesão php migrar.

feito funcionará

Vicky
fonte
13

No meu caso, apenas altero a ordem das migrações são executadas manualmente para que os usuários da tabela sejam criados primeiro.

Na pasta database / migrations / seu nome de arquivo de migração, tenha este formato: year_month_day_hhmmss_create_XXXX_table.php

Apenas renomeie o arquivo de usuário de criação para que a data de criação da tabela de prioridades da tabela seja definida depois da data do usuário (até um segundo depois é suficiente)

ldt
fonte
13

No laravel 5.8, a tabela users_ utiliza o bigIncrements('id')tipo de dados para a chave primária. Portanto, quando você desejar consultar uma restrição de chave estrangeira, sua user_idcoluna precisará ser do unsignedBigInteger('user_id')tipo.

Dhara Talaviya
fonte
muito obrigado, eu passei uma hora tentando descobrir por que a chave estrangeira está causando a exceção
Ya Basha
10

Eu estava tendo o mesmo problema usando o Laravel 5.8. Depois de examinar melhor os documentos do laravel, além disso, aqui Migrações e bigIncrements . A maneira como resolvi isso foi adicionando chaves primárias "$ table-> bigIncrements ('id')" a todas as tabelas relacionadas à tabela "users" e suas associações, no meu caso a tabela "role" . Por fim, tive "$ table-> unsignedBigInteger" para associar funções a usuários (muitos-para-muitos), ou seja, tabela "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']);
        });
Capfer
fonte
9

Eu tive esse problema com o laravel 5.8 e corrigi esse código, como mostrado aqui na documentação do Laravel , para onde quer que eu esteja adicionando uma chave estrangeira.

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

então eu corri $ php artisan migrate:refresh

Como essa sintaxe é bastante detalhada, o Laravel fornece métodos adicionais de terser que usam convenção para fornecer uma melhor experiência ao desenvolvedor. O exemplo acima pode ser escrito assim:

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

O uso do Laravel 5.3 teve o mesmo problema.

A solução foi usar unsignedInteger em vez de número inteiro ('nome') -> unsigned () .

Então é isso que funcionou

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

A razão pela qual isso funcionou é o fato de que ao usar número inteiro ('nome') -> não assinado, a coluna criada na tabela tinha comprimento 11, mas ao usar unsigedInteger ('nome'), a coluna tinha comprimento 10.

Comprimento 10 é o comprimento das chaves primárias ao usar o Laravel, de modo que o comprimento das colunas corresponda.

Radu Diță
fonte
Cara, obrigado por isso, eu estava prestes a desistir e executar o sql bruto como acabei de encontrar sua postagem. Vou precisar ler mais sobre por que a chave primária do laravel é forçada a ter o comprimento 10 e se existe alguma razão pela qual fazer inteiro ('coluna') -> unsigned () deve ser diferente de unsigedInteger ('column')
Arnaud Bouchot 10/01
6

Esse erro ocorreu para mim porque - enquanto a tabela que eu estava tentando criar era o InnoDB - a tabela estrangeira com a qual eu estava tentando relacioná-la era uma tabela MyISAM!

bagnap
fonte
O MyISAM não suporta restrições de chave estrangeira. Provavelmente funcionou porque a mudança para o MyISAM fez com que ele ignorasse completamente a chave estrangeira que provavelmente estava lá por um motivo. Seja cuidadoso.
greggle138
5

Não podemos adicionar relações, a menos que tabelas relacionadas sejam criadas. O Laravel executa migrações ordenadas por data dos arquivos de migração. Portanto, se você deseja criar uma relação com uma tabela que existe no segundo arquivo de migração, ela falha.

Como enfrentei o mesmo problema, criei finalmente mais um arquivo de migração para especificar todas as relações.

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');
    });
Pavan Kumar
fonte
1
como você nomeou o arquivo? 9999_99_99_999999_create_foreign_keys.php?
Iannazzi
adicionar 9999_99_99_99999 ao nome do arquivo de migração é uma má ideia, pois irá estragar o recurso de reversão.
Maulik Gangani
5

Esteja ciente: quando o Laravel configura uma tabela usando

$table->increments('id');

que é padrão na maioria das migrações, isso configurará um campo inteiro não assinado. Portanto, ao fazer uma referência estrangeira de outra tabela para este campo, verifique se na tabela de referência você define o campo como UnsignedInteger e não (o que eu supunha ser um) campo UnsignedBigInteger.

Por exemplo: no arquivo de migração 2018_12_12_123456_create_users_table.php:

Schema::create('users', function (Blueprint $table){
    $table->increments('id');
    $table->string('name');
    $table->timestamps();

Em seguida, no arquivo de migração 2018_12_12_18000000_create_permissions_table.php, que configura a referência estrangeira novamente para os usuários:

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

Você deve escrever desta maneira

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

O campo de chave estrangeira deve estar sem sinal , espero que ajude !!

Mahesh Yadav
fonte
Não apenas não assinado, mas quando ele faz referência a uma coluna bigIncrements, deve ser unsigedBigInteger
gondwe
4

Para fazer adição de restrição de chave estrangeira no laravel, o seguinte funcionou para mim:

  1. Crie a coluna para ser chave estrangeira da seguinte maneira:

    $ table-> inteiro ('nome_da_coluna') -> não assinado ();
  2. Adicionando a linha de restrição imediatamente após (1) ou seja,

    $ table-> inteiro ('nome_da_coluna') -> não assinado ();
    $ table-> estrangeira ('nome_da_coluna') -> referências ('pk_of_other_table') -> on ('outra_tabela');
bmnepali
fonte
3

Eu sei que é uma pergunta antiga, mas verifique se você está trabalhando com referências, o mecanismo de suporte adequado está definido. configure o mecanismo innodb para as duas tabelas e o mesmo tipo de dados para as colunas de referência

$table->engine = 'InnoDB';
di3
fonte
2

Fazendo uma pausa aqui alguns anos após a pergunta original, usando o laravel 5.1, tive o mesmo erro que minhas migrações foram geradas por computador com o mesmo código de data. Passei por todas as soluções propostas e depois refatorado para encontrar a fonte do erro.

Nas laracasts seguintes e na leitura dessas postagens, acredito que a resposta correta é semelhante à resposta de Vickies, com a exceção de que você não precisa adicionar uma chamada de esquema separada. Você não precisa pôr a mesa no Innodb, estou assumindo que o laravel está fazendo isso agora.

As migrações simplesmente precisam ser cronometradas corretamente, o que significa que você modificará o código da data (mais tarde) no nome do arquivo para tabelas nas quais você precisa de chaves estrangeiras. Como alternativa ou além disso, abaixe o código de dados para tabelas que não precisam de chaves estrangeiras.

A vantagem na modificação do código de dados é que seu código de migração será mais fácil de ler e manter.

Até agora, meu código está funcionando, ajustando o código de tempo para atrasar migrações que precisam de chaves estrangeiras.

No entanto, tenho centenas de tabelas, portanto, no final, tenho uma última tabela apenas para chaves estrangeiras. Apenas para fazer as coisas fluírem. Estou assumindo que vou puxá-los para o arquivo correto e modificar o código de dados como eu testá-los.

Por exemplo, um arquivo: file 2016_01_18_999999_create_product_options_table. Este precisa que a tabela de produtos seja criada. Veja os nomes dos arquivos.

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

a tabela de produtos: isso precisa migrar primeiro. 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');
}

E, finalmente, no final do arquivo que estou usando temporariamente para resolver problemas, que refatorarei ao escrever testes para os modelos que chamei 9999_99_99_999999_create_foreign_keys.php. Essas chaves são comentadas quando eu as puxei, mas você entendeu.

    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');
//        });
Iannazzi
fonte
2

Tão simples !!!

se o seu primeiro 'priorities'arquivo de migração for criado , o Laravel será executado pela primeira vez 'priorities'enquanto a 'users'tabela não existir.

como ele pode adicionar relação a uma tabela que não existe!

Solução: retire os códigos de chave estrangeira da 'priorities'tabela. seu arquivo de migração deve ser assim:

insira a descrição da imagem aqui

e adicione a um novo arquivo de migração, aqui está o nome create_prioritiesForeignKey_tablee adicione estes códigos:

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

certifique-se de que sua coluna de estrangulamento esteja com muita raiva da coluna-chave de estrangulamento

Quero dizer que sua chave externa (na segunda tabela) deve ser o mesmo tipo da sua chave principal do ponter (na primeira tabela)

sua chave principal do ponteiro deve ser um método não assinado, deixe-me mostrar:

na sua PRIMEIRA tabela de migração:

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

na sua SEGUNDA tabela de migração:

$table->integer('column_forein_name')->unsigned(); //this must be INTEGER and UNSIGNED
$table->foreign('column_forein_name')->references('column_name')->on('first_table_name');

OUTRO EXEMPLO PARA VER DIFERENÇA

na sua PRIMEIRA tabela de migração:

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

na sua SEGUNDA tabela de migração:

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

VER INTERVALOS DE TABELA DE TIPOS NUMÉRICOS MYSQL

Rubén Ruíz
fonte
2

Uma coisa que notei é que, se as tabelas usarem um mecanismo diferente da restrição de chave estrangeira, não funcionará.

Por exemplo, se uma tabela usar:

$table->engine = 'InnoDB';

E os outros usos

$table->engine = 'MyISAM';

geraria um erro:

SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint

Você pode corrigir isso adicionando o InnoDB no final da criação da tabela da seguinte maneira:

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
    });
}
erlandmuchasaj
fonte
1

No meu caso, eu estava referenciando uma coluna inteira id em uma coluna de string user_id . Eu mudei:

$table->string('user_id')

para:

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

Espero que ajude alguém!

Raphael Rafatpanah
fonte
1

A essência é que o método estrangeiro usa ALTER_TABLEpara transformar um campo preexistente em uma chave estrangeira. Então você precisa definir o tipo de tabela antes de aplicar a chave estrangeira. No entanto, ele não precisa estar em uma Schema::chamada separada . Você pode fazer as duas coisas no create, assim:

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

Observe também que o tipo de user_idestá definido como não assinado para corresponder à chave estrangeira.

Menasheh
fonte
1

Você pode passar diretamente o parâmetro booleano na coluna número inteiro dizendo que ele deve estar sem sinal ou não. No laravel 5.4, o código a seguir resolveu meu problema.

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

Aqui, o segundo parâmetro false representa que não deve ser incrementado automaticamente e o terceiro parâmetro true representa que não deve ser assinado. Você pode manter a restrição de chave estrangeira na mesma migração ou separá-la. Funciona em ambos.

Mohit Satish Pawar
fonte
1

Se nenhuma das soluções acima funcionar para iniciantes, verifique se os dois IDs têm o mesmo tipo: ambos são integerou ambos são bigInteger, ... Você pode ter algo parecido com isto:

Tabela principal (usuários por exemplo)

$table->bigIncrements('id');

Tabela filho (prioridades por exemplo)

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

Essa consulta falhou porque users.idé um BIG INTEGERconsiderando que priorities.user_idé um INTEGER.

A consulta correta nesse caso seria a seguinte:

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

No meu caso, não funcionou até eu executar o comando

composer dump-autoload

Dessa forma, você pode deixar as chaves estrangeiras dentro do esquema de criação

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');
}
Vladimir Salguero
fonte
1

Também pode ser a ordem de migração da criação. Se você primeiro criar a tabela de prioridades e depois da tabela de usuários, ela estará errada. Por causa da primeira migração, procurando a tabela de usuários. Então, você deve alterar a ordem da migração em

app/database/migrations

diretório

Turan Zamanlı
fonte
1

Para mim, a coluna da tabela que minha tabela filha referenciou não foi indexada.

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

Ignore o nome terrível, é de outro sistema terrivelmente projetado.

Conceder
fonte
1

Às vezes, esse erro pode ocorrer devido à sequência de migrações.

Like Users e Order são duas tabelas

A tabela de pedidos possui a chave estrangeira dos usuários (durante a migração, se a tabela de pedidos migrar primeiro, isso causará o problema porque não há usuários que correspondam à chave estrangeira)

Solução: basta colocar a tabela Atualização de pedidos sob os usuários para atualização

Exemplo: No meu caso, tabelas Educação e Universidade Tabela Educação

public function up()
{
    Schema::create('doc_education', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('uni_id')->unsigned()->nullable();
        $table->timestamps();
    });
}

Na Universidade

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

Uma coisa que acho que falta nas respostas aqui e me corrija se estiver errado, mas as chaves estrangeiras precisam ser indexadas na tabela dinâmica. Pelo menos no mysql, esse parece ser o caso.

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

}
Ossi
fonte