Migration: impossible d'ajouter une contrainte de clé étrangère

207

J'essaie de créer des clés étrangères dans Laravel cependant quand je migre ma table en utilisant artisanje reçois l'erreur suivante:

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

Mon code de migration est le suivant:

fichier de migration des priorités

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

fichier de migration des utilisateurs

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

Toutes les idées sur ce que j'ai fait de mal, je veux l'obtenir maintenant, car j'ai beaucoup de tableaux que je dois créer, par exemple utilisateurs, clients, projets, tâches, statuts, priorités, types, équipes. Idéalement, je veux créer des tables qui contiennent ces données avec les clés étrangères, i..e clients_projectet project_tasksetc.

J'espère que quelqu'un pourra m'aider à démarrer.

001221
la source

Réponses:

357

Ajoutez-le en deux étapes, et il est bon de le rendre non signé aussi:

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
la source
117
Merci, Antonio! Pour moi, le problème n'a pas été d'ajouter unsigned () sur la colonne user_id afin qu'il corresponde au type de données de la colonne id sur la table des utilisateurs. La fonction increments ('id') de Laravel crée un entier non signé, de sorte que la colonne de clé étrangère doit également être non signée.
Brad Griffith
7
l'ajout de non signé, à part la séparation de la Schema::tableméthode, a aidé! Merci!
patrickjason91
4
Pour moi, cela ne rendait pas l'ID non signé également. Merci pour le conseil.
Carl Weis
6
La solution se trouve dans le commentaire de @BradGriffith. Comme indiqué ci-dessus, il n'est pas nécessaire de se séparer du tout. Peut-être préférable de mettre à jour la réponse en conséquence.
Matanya
12
Utilisez $table->unsignedBigInteger('user_id')si votre user.id estbigIncrements
Maksim Ivanov
114

Question déjà répondu, mais j'espère que cela pourrait aider quelqu'un d'autre.

Cette erreur s'est produite pour moi car j'ai d'abord créé la table de migration avec la clé étrangère avant que la clé n'existe en tant que clé primaire dans sa table d'origine. Les migrations sont exécutées dans l'ordre dans lequel elles ont été créées, comme indiqué par le nom de fichier généré après l'exécution migrate:make. Par exemple 2014_05_10_165709_create_student_table.php.

La solution était de renommer le fichier avec la clé étrangère à une date antérieure à celle du fichier avec la clé primaire, comme recommandé ici: http://forumsarchive.laravel.io/viewtopic.php?id=10246

Je pense que je devais aussi ajouter $table->engine = 'InnoDB';

haakym
la source
4
Après avoir renommé le fichier de migration et obtenez des erreurs comme: Échec de l'ouverture du flux: aucun fichier ou répertoire (et l'ancien nom de migration est affiché), vous devez exécuter: composer dump-autoload
Stelian
14
$ table-> engine = 'InnoDB'; est requis pour appliquer la clé étrangère au niveau MySql. Le moteur laravel par défaut est MyIsam qui ne prend pas en charge les clés étrangères!
François Breton
2
cela a également fonctionné pour moi, merci. Mais cela me semble un peu étrange que cela fonctionne de cette façon. Je veux dire, cela a du sens, mais il devrait y avoir un moyen de spécifier l'ordre d'exécution de la migration autre que de renommer manuellement les fichiers et de trouver de fausses dates dans le processus
allisius
2
Je suis venu ici non pas parce que j'obtenais des erreurs, mais j'ai pu ajouter des valeurs incorrectes à la colonne qui était une clé étrangère. Ensuite, j'ai vu le commentaire et la réponse sur InnoDB. C'était bon à savoir. Merci les gars :)
SuperNOVA
2
L'ordre dans lequel vous avez créé vos migrations reste important lors de la migration. J'ai rencontré ce problème mais cela l'a résolu.
mugabits
60

Laravel ^ 5.8

Depuis Laravel 5.8 , les stubs de migration utilisent la méthode bigIncrements sur les colonnes ID par défaut. Auparavant, les colonnes d'ID étaient créées à l'aide de la méthode d'incréments.

Cela n'affectera aucun code existant dans votre projet; toutefois, sachez que les colonnes de clé étrangère doivent être du même type . Par conséquent, une colonne créée à l'aide de la méthode increments ne peut pas référencer une colonne créée à l'aide de la méthode bigIncrements.

Source: Migrations & bigIncrements


Exemple

Imaginons que vous construisez une application simple basée sur les rôles et que vous ayez besoin de référencer user_id dans la table 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');
    });
}

Comme vous pouvez le voir, la ligne commentée lèvera une exception de requête, car, comme mentionné dans les notes de mise à niveau, les colonnes de clé étrangère doivent être du même type , vous devez donc soit changer la clé étrangère (dans cet exemple, c'est user_id ) en bigInteger dans la table role_user ou remplacez la méthode bigIncrements par la méthode increments dans la table users et utilisez la ligne commentée dans le tableau croisé dynamique , c'est à vous.


J'espère avoir pu clarifier cette question pour vous.

chebaby
la source
1
Je vous remercie. tu m'as sauvé la vie. Suite à votre explication, j'ai changé ma clé étrangère en bigInteger comme vous l'avez suggéré. 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'); } Ça a marché. Je vous remercie.
Bruce Tong
1
@BruceTong, je suis content d'avoir pu aider.
chebaby
1
Oui, c'est la réponse la plus pertinente.
Mohd Abdul Mujib
1
Cette réponse est très utile.
Karim Pazoki
1
Meilleure réponse. Merci
VishalParkash
49

Dans mon cas, le problème était que la table principale contenait déjà des enregistrements et je forçais la nouvelle colonne à ne pas être NULL. Donc, l'ajout d'un -> nullable () à la nouvelle colonne a fait l'affaire. Dans l'exemple de la question serait quelque chose comme ceci:

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

ou:

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

J'espère que cela aide quelqu'un!

AdrianCR
la source
Notez que la colonne 'id' de votre table parent doit également être non signée! Utiliser une ligne telle que $ table-> increments ('id'); passera automatiquement par défaut à non signé.
Colin Stadig
Cela a fonctionné pour moi. J'ai changé le type de données de l'ID de la table parent de BigIncrements en incréments.
Emmanuel Benson
22

Dans mon cas, le problème était que la migration générée automatiquement pour la userstable était

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

J'ai donc dû changer le type de colonne


$table->bigInteger('id');

pour faire ma migration avec la clé étrangère.

Ceci avec laravel 5.8.2

Daniele
la source
Parce que la colonne de clé étrangère doit avoir le même type de la colonne à laquelle elle se réfère
Daniele
9
Cela a fonctionné pour moi $ table-> unsignedBigInteger ('user_id'); dans laravel 5.8. *
Adam Winnipass
J'ai également eu ce problème avec 5.8, cela l'a résolu pour moi! Merci!
Mike Sheward
M'a sauvé d'une longue nuit!
chq
19

Dans mon cas, le problème était avec le calendrier de migration, soyez prudent lors de la création de migrations, créez d'abord la migration enfant que la migration de base. Parce que si vous créez d'abord la migration de base, votre clé étrangère recherchera une table enfant et il n'y aura pas de table qui lèvera ensuite une exception.

En outre:

Lorsque vous créez une migration, elle a un horodatage au début. disons que vous avez créé un chat de migration pour qu'il ressemble 2015_08_19_075954_the_cats_time.phpet qu'il ait ce code

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

Et après avoir créé la table de base, vous créez une autre race de migration qui est une table enfant, elle a sa propre heure et date de création. Le code ressemblera à:

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

il semble que ces deux tables soient correctes mais lorsque vous exécutez php artisan migrate . Il lèvera une exception car la migration créera d'abord la table de base dans votre base de données car vous avez créé cette migration en premier et notre table de base contient une contrainte de clé étrangère qui recherchera la table enfant et la table enfant n'existe pas, ce qui est probablement une exception..

Alors:

Créez d'abord la migration de la table enfant.

Créez la migration de la table de base après la création de la migration enfant.

l'artisan php migre.

cela fonctionnera

Vicky
la source
13

Dans mon cas, je modifie simplement l'ordre dans lequel les migrations sont exécutées manuellement afin que les utilisateurs de table soient créés en premier.

Dans le dossier base de données / migrations / votre nom de fichier de migration a ce format: year_month_day_hhmmss_create_XXXX_table.php

Renommez simplement créer un fichier utilisateur pour que la date de création de votre table de priorités de table soit définie plus tard que la date utilisateur (même une seconde plus tard suffit)

ldt
la source
13

Dans laravel 5.8, la table users_table utilise bigIncrements('id')le type de données pour la clé primaire. Ainsi, lorsque vous souhaitez référencer une contrainte de clé étrangère, votre user_idcolonne doit être de unsignedBigInteger('user_id')type.

Dhara Talaviya
la source
merci beaucoup, j'ai passé une heure à essayer de comprendre pourquoi la clé étrangère est à l'origine de l'exception
Ya Basha
10

J'avais le même problème en utilisant Laravel 5.8. Après avoir regardé de plus près les documents laravel, découvrez ici Migrations & bigIncrements . Je l'ai résolu en ajoutant des clés primaires "$ table-> bigIncrements ('id')" à chaque table liée à la table "users" et à ses associations, dans mon cas la table "role" . Enfin, j'avais "$ table-> unsignedBigInteger" pour associer des rôles aux utilisateurs (plusieurs à plusieurs), c'est-à-dire la table "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
la source
9

J'ai eu ce problème avec laravel 5.8 et j'ai corrigé ce code, comme indiqué ici dans la documentation de Laravel , à l'endroit où j'ajoute une clé étrangère.

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

alors j'ai couru $ php artisan migrate:refresh

Étant donné que cette syntaxe est plutôt verbeuse, Laravel fournit des méthodes de terser supplémentaires qui utilisent la convention pour fournir une meilleure expérience de développeur. L'exemple ci-dessus pourrait être écrit comme suit:

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

L'utilisation de Laravel 5.3 a eu le même problème.

La solution consistait à utiliser unsignedInteger au lieu de integer ('name') -> unsigned () .

Voilà donc ce qui a fonctionné

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

La raison pour laquelle cela a fonctionné est le fait que lorsque vous utilisez entier ('nom') -> non signé, la colonne créée dans la table a une longueur de 11, mais lorsque vous utilisez unsigedInteger ('nom') la colonne avait une longueur 10.

La longueur 10 est la longueur des clés primaires lorsque vous utilisez Laravel, la longueur des colonnes correspond donc.

Radu Diță
la source
Mec, merci pour ce que j'étais sur le point d'abandonner et d'exécuter le SQL brut car je viens de trouver votre message. Je vais devoir en savoir plus sur les raisons pour lesquelles la clé primaire de laravel est forcée d'être de longueur 10 et s'il y a une raison pour laquelle faire entier ('colonne') -> unsigned () devrait être différent de unsigedInteger ('colonne')
Arnaud Bouchot
6

Cette erreur s'est produite pour moi parce que - alors que la table que j'essayais de créer était InnoDB - la table étrangère à laquelle j'essayais de la relier était une table MyISAM!

bagnap
la source
MyISAM ne prend pas en charge les contraintes de clé étrangère. Cela a probablement fonctionné car le passage à MyISAM l'a fait ignorer complètement la clé étrangère qui était probablement là pour une raison. Faites attention.
greggle138
5

Nous ne pouvons pas ajouter de relations, sauf si des tables associées sont créées. Laravel exécute les migrations par ordre de date des fichiers de migration. Donc, si vous souhaitez créer une relation avec une table qui existe dans le 2e fichier de migration, cela échoue.

J'ai rencontré le même problème, j'ai donc finalement créé un fichier de migration pour spécifier toutes les relations.

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
la source
1
comment avez-vous nommé le fichier? 9999_99_99_999999_create_foreign_keys.php?
Iannazzi
l'ajout de 9999_99_99_99999 au nom de fichier de migration est une mauvaise idée car cela va bousiller la fonction de restauration.
Maulik Gangani
5

Attention: lorsque Laravel met en place une table en utilisant

$table->increments('id');

qui est standard dans la plupart des migrations, cela créera un champ entier non signé. Par conséquent, lorsque vous créez une référence étrangère d'une autre table à ce champ, assurez-vous que dans la table de référence, vous définissez le champ sur UnsignedInteger et non (ce que je supposais être un) UnsignedBigInteger.

Par exemple: dans le fichier de migration 2018_12_12_123456_create_users_table.php:

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

Ensuite, dans le fichier de migration 2018_12_12_18000000_create_permissions_table.php, qui configure la référence étrangère aux utilisateurs:

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
la source
5

Vous devez écrire de cette façon

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

Le champ de clé étrangère ne doit pas être signé , j'espère que cela aide !!

Mahesh Yadav
la source
Non seulement non signé mais lorsqu'il fait référence à une colonne bigIncrements, il doit être unsigedBigInteger
gondwe
4

Pour faire l'ajout d'une contrainte de clé étrangère dans laravel, ce qui suit a fonctionné pour moi:

  1. Créez la colonne comme clé étrangère comme suit:

    $ table-> entier ('nom_colonne') -> unsigned ();
  2. Ajout de la ligne de contrainte immédiatement après (1) ie

    $ table-> entier ('nom_colonne') -> unsigned ();
    $ table-> étranger ('nom_colonne') -> références ('pk_of_other_table') -> on ('autre_table');
bmnepali
la source
3

Je sais que c'est une vieille question, mais assurez-vous que si vous travaillez avec des références, le moteur de support approprié est défini. définir le moteur innodb pour les deux tables et le même type de données pour les colonnes de référence

$table->engine = 'InnoDB';
di3
la source
2

J'interviens ici quelques années après la question d'origine, en utilisant laravel 5.1, j'ai eu la même erreur car mes migrations ont été générées par ordinateur avec le même code de date. J'ai parcouru toutes les solutions proposées, puis refactorisé pour trouver la source d'erreur.

En suivant les laracasts et en lisant ces articles, je pense que la bonne réponse est similaire à la réponse de Vickies, à l'exception que vous n'avez pas besoin d'ajouter un appel de schéma distinct. Vous n'avez pas besoin de mettre la table sur Innodb, je suppose que laravel le fait maintenant.

Les migrations doivent simplement être chronométrées correctement, ce qui signifie que vous modifierez le code de date (plus tard) dans le nom de fichier des tables sur lesquelles vous avez besoin de clés étrangères. Alternativement ou en plus, abaissez le code de données pour les tables qui n'ont pas besoin de clés étrangères.

L'avantage de la modification du code de données est que votre code de migration sera plus facile à lire et à maintenir.

Jusqu'à présent, mon code fonctionne en ajustant le code temporel pour repousser les migrations qui nécessitent des clés étrangères.

Cependant, j'ai des centaines de tables, donc à la fin j'ai une dernière table pour les clés étrangères. Juste pour faire bouger les choses. Je suppose que je vais les extraire dans le bon fichier et modifier le code de données pendant que je les teste.

Donc un exemple: fichier 2016_01_18_999999_create_product_options_table. Celui-ci nécessite la création de la table produits. Regardez les noms de fichiers.

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

la table des produits: celle-ci doit d'abord migrer. 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');
}

Et enfin à la toute fin le fichier que j'utilise temporairement pour résoudre les problèmes, que je vais refactoriser en écrivant des tests pour les modèles que j'ai nommés 9999_99_99_999999_create_foreign_keys.php. Ces clés sont commentées lorsque je les ai retirées, mais vous comprenez.

    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
la source
2

Si simple !!!

si votre premier 'priorities'fichier de migration de création , Laravel s'exécute d'abord 'priorities'alors que la 'users'table n'existe pas.

comment il peut ajouter une relation à une table qui n'existe pas!.

Solution: retirez les codes de clé étrangère du 'priorities'tableau. votre fichier de migration doit ressembler à ceci:

entrez la description de l'image ici

et ajouter à un nouveau fichier de migration, voici son nom create_prioritiesForeignKey_tableet ajoutez ces codes:

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

assurez-vous que votre colonne étrangère est sur une large rage de colonne clé étrangère

Je veux dire que votre clé étrangère (dans le deuxième tableau) doit être du même type que votre clé ponteuse principale (dans le premier tableau)

votre clé principale de pointeur doit être ajouter une méthode non signée, permettez-moi de montrer:

sur votre première table de migration:

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

sur votre deuxième table de migration:

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

UN AUTRE EXEMPLE POUR VOIR LA DIFFÉRENCE

sur votre première table de migration:

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

sur votre deuxième table de migration:

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

VOIR LES PLAGES DE TABLEAUX DES TYPES NUMÉRIQUES MYSQL

Rubén Ruíz
la source
2

Une chose que j'ai remarquée est que si les tables utilisent un moteur différent, la contrainte de clé étrangère ne fonctionne pas.

Par exemple, si une table utilise:

$table->engine = 'InnoDB';

Et les autres utilisations

$table->engine = 'MyISAM';

générerait une erreur:

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

Vous pouvez résoudre ce problème en ajoutant simplement InnoDB à la fin de la création de votre table comme ceci:

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
la source
1

Dans mon cas, je faisais référence à une colonne entière id sur une colonne de chaîne user_id . J'ai changé:

$table->string('user_id')

à:

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

J'espère que cela aide quelqu'un!

Raphael Rafatpanah
la source
1

L'essentiel est que la méthode étrangère utilise ALTER_TABLEpour transformer un champ préexistant en clé étrangère. Vous devez donc définir le type de table avant d'appliquer la clé étrangère. Cependant, il n'est pas nécessaire que ce soit dans un Schema::appel distinct . Vous pouvez faire les deux dans create, comme ceci:

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

Notez également que le type de user_idest défini sur non signé pour correspondre à la clé étrangère.

Menasheh
la source
1

Vous pouvez directement passer le paramètre booléen dans la colonne entière en disant qu'il doit être non signé ou non. Dans laravel 5.4, le code suivant a résolu mon problème.

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

Ici, le deuxième paramètre false indique qu'il ne doit pas être auto-incrémenté et le troisième paramètre true représente qu'il ne doit pas être signé. Vous pouvez conserver la contrainte de clé étrangère dans la même migration ou la séparer. Cela fonctionne sur les deux.

Mohit Satish Pawar
la source
1

Si aucune des solutions ci-dessus ne fonctionne pour les débutants, vérifiez si les deux ID ont le même type: les deux sont integer ou les deux le sontbigInteger , ... Vous pouvez avoir quelque chose comme ceci:

Table principale (utilisateurs par exemple)

$table->bigIncrements('id');

Table enfant (priorités par exemple)

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

Cette requête échouera car users.idest un BIG INTEGERtandis que priorities.user_idest un INTEGER.

La bonne requête dans ce cas serait la suivante:

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

Dans mon cas, cela n'a pas fonctionné jusqu'à ce que j'exécute la commande

composer dump-autoload

de cette façon, vous pouvez laisser les clés étrangères à l'intérieur du schéma de création

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
la source
1

Cela peut également être votre ordre de migration de création. Si vous créez d'abord la table des priorités, et après la table des utilisateurs, ce sera faux. En raison de la première migration à la recherche d'une table d'utilisateurs. Vous devez donc modifier l'ordre de migration sur

app/database/migrations

annuaire

Turan Zamanlı
la source
1

Pour moi, la colonne de table référencée par ma table enfant n'a pas été indexée.

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

Ignorez la terrible appellation, c'est d'un autre système terriblement conçu.

Subvention
la source
1

Parfois, cette erreur peut survenir en raison d'une séquence de migrations.

Comme les utilisateurs et l'ordre sont deux tableaux

La table de commande a la clé foriegn des utilisateurs (pendant la migration si la table de commande migre en premier, cela causera le problème car aucun utilisateur ne correspond à la clé étrangère)

Lösung: Mettez juste votre table de mise à jour de commande sous les utilisateurs pour la mise à jour

Exemple: Dans mon cas, Tableaux de l'éducation et de l'université Tableau de l'éducation

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

À l'Université

    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
la source
0

Je pense qu'une chose manque dans les réponses ici, et corrigez-moi si je me trompe, mais les clés étrangères doivent être indexées sur le tableau croisé dynamique. Au moins dans mysql, cela semble être le cas.

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
la source