Laravel Migration to add foreign key not working - php

I am back adding foreign keys to some tables but this one is not working.
Schema::table('users', function(Blueprint $table){
$table->integer('account_type')->unsigned()->change();
$table->foreign('account_type')
->references('id')
->on('account_types');
});
It throws these 3 errors in terminal:
[Illuminate\Database\QueryException] SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint (SQL: alter table `users` add constraint `users_account_type_foreign` foreign key (`account_type`) references `account_types` (`id`))
[Doctrine\DBAL\Driver\PDOException]SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint
[PDOException] SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint
Any idea what I need to do to fix this? I wan't to be able to click on the account_type field in my users table and be taken to the related account type in the account_types table whilst using SequelPro.

If we assume that you've already created account_types and users, then this is what you could do.
Run this command to create a new migration.
php artisan make:migration add_account_type_to_users
Then add this to your up function, what this will do is update the already existing users table, with adding a column account_type and then adding the foreign key to the account_types table.
public function up()
{
Schema::table('users', function(Blueprint $table) {
$table->integer('account_type')->unsigned();
$table->foreign('account_type')->references('id')->on('account_types');
});
}
Then add this to your down function, to allow the migration to run smoothly incase of future changes and/or a refresh.
public function down()
{
Schema::table('users', function(Blueprint $table) {
$table->dropColumn('account_type');
});
}
I am assuming your issue is with the dating of the migration files - I would advice you to go over them and make sure they get executed in the right order.

I suggest that you create a migration specifically to add the foreign key constraint. Migrations should be created in such a way that each change to your database is a NEW migration. That way if something goes wrong, you can roll it back. "Back adding" as you said you were doing is likely the root of the problem. Like some users have suggested, the order in which your migrations are created is critical to how the database is built. And you must have created both participating tables in order to create a foreign key constaint on them.

Your table 'account_type' need to be created before 'users' table.
Basically on Laravel, users table is the first created, to resolve it you can put all schema on One migration file. or you need to change the date in the name of the users file, because laravel execute migrations in name order.
I make my migration like this :
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class DatabaseContent extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
$connection = config('database.default');
Schema::connection($connection)->create('account_type', function
(Blueprint $table) {
// Own Method
}
Schema::connection($connection)->create('users', function
(Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});

Related

Foreign key constraint is incorrectly formed in Laravel

I am using Laravel 7 and PHP 7.4.
I'm working on databases and suddenly stuck over issue when I'm trying to generate a foreign key for user in another table. It should be straight away process and I'm following the doc, still getting error.
General error: 1005 Can't create table carchain_qrcode.sellers (errno: 150 "Foreign key constraint is incorrectly formed
User Table
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->bigInteger('id');
$table->string('name')->unique();
$table->string('email')->unique();
});
}
Sellers Table
public function up()
{
Schema::create('sellers', function (Blueprint $table) {
$table->bigInteger('id');
$table->unsignedBigInteger('user_id');
$table->string('seller_name');
$table->string('seller_email');
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
});
Where have I gone wrong?
I think the problem is that the id of your users table is bigInteger and not bigIncrements or unsignedBigInteger.
In Laravel 7 you can simply do: $table->id() to create the id column.
Short: For quick fix refer to #Aless55 answer. The main thing to keep in mind is that id and foreign_key column types should match.
Correct way:
It is better to use Laravel's built-in APIs for creating primary key and foreign key. More details here:
It will automatically take care of column types, creating indexes, and so on. In addition, sticking to official documentation makes it easy to understand the code by others, and maintain it by the developer (It is just my opinion).
In your case:
Users table
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name')->unique();
$table->string('email')->unique();
});
}
Sellers table:
public function up()
{
Schema::create('sellers', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained(); // this will automatically detect which table to reference
$table->string('seller_name');
$table->string('seller_email');
});
}
this error occured due to incorrect data type used on the foreign key which you are going to create. The primary key data type on the users table should be same as the data type which you used in Sellers table as below:
Users Table
$table->id();
Sellers Table
$table->unsignedBigInteger('user_id');
or if you used any other data type on users table primary key then the foreign key in the other table should be same accordingly.

Add cascade/delete functionality to existing migration

I have 2 tables in my database. One for Courses and one for Course Chapters.
The migration for the courses looks like this:
Schema::create('courses', function (Blueprint $table) {
$table->bigIncrements('id');
$table->timestamps();
});
The migration for the chapters looks like this:
Schema::create('course_chapters', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('course_id');
$table->timestamps();
});
I want the course and the chapter to cascade down, so when i delete a course, the chapter also will be deleted.
Some examples i saw make use of deleting the foreign key but I never signed my column as a foreign key.
For example, normally, I could:
$table->dropForeign('course_id');
$table->foreign('course_id')
->references('id')->on('courses')
->onDelete('cascade');
How can i accomplish this in a (preferably) new migration and on what table should i add the foreign key?
This as it is should go on your course_chapters table:
$table->foreign('course_id')->references('id')->on('courses')->onDelete('cascade');
You don't need to add $table->dropForeign('course_id'); because that will drop the foreign key from the column.
NOTE: and this:
$table->unsignedInteger('course_id');
Should be this:
$table->unsignedBigInteger('course_id');
Because it will throw an error of using different data types.

Reciproc relationship migration order in Laravel

I am trying to create a relationship in Laravel Migration:
User > has many > Images
User > has one > Image (image_id) <-- Avatar
Image > belongsTo > User (user_id)
If I will create the migration with references to mark the relationships, the migration will fail because image needs User, and User needs image.
How should I order migrations to prevent this from happening?
(https://laravel.com/docs/5.4/migrations)
You can create users and images tables in any order and add foreign key constrains in the second migration after creating the table. Or even in a separate migration file.
To add constrains use table() method instead of create():
Schema::table('images', function (Blueprint $table) {
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});

Laravel Many to Many Pivot on existing Pivot

I have a situation in Laravel 5.1 where I would like to add a many-to-many relationship to an existing relationship. According to the diagram below, I already have all the items in green working.
The issue is that since there isn't a primary key on the issue_person table, I don't know how to add a many-to-many relationship to Users. Does anyone know how I would go about accomplishing this?
So it appears that a simple answer to this is to write a migration that adds a primary key to the original issue_person pivot table, and then set up a many-to-many relationship between issue_person and user using the position_user table.
My migration looks like this:
public function up()
{
Schema::table('issue_person', function (Blueprint $table) {
$table->increments('id');
});
}
public function down()
{
Schema::table('issue_person', function (Blueprint $table) {
$table->dropColumn('id');
});
}

Laravel migration foreign keys

I'm trying to build some relationships in Laravel, i'm a little confused about relationships and migrations. Here is a simple example of what i'm doing:
Users -> has_many -> Cats
So my Users migration file has a relationship to Cats like so:
$table->foreign('cats_id')->references('id')->on('cats')
But when I run my migration, I get:
Error: relation cats does not exist...
Do I need to build the Cats table before the Users table?
Do I also need to specify the foreign relation between the two, or if the models contain "hasMany" and "belongsTo" wouldn't Laravel build those relationships automatically on migration?
Do I actually need migrations?
You can't reference a table that not exists. It has nothing to do with Laravel or Eloquent, it's (My)SQL thing.
First create the parent table users, then the child table cats referencing the first:
$table->foreign('user_id')->references('id')->on('users')
this is how User hasMany Cat would look like. cats table has foreign key referencing users table, not the other way around like you tried.
You need to set the foreign key to the table where the 'many' are.
$table->foreign('id')->references('cats_id')->on('Users')
You need to make sure that
Table 'Users' exists before you create table Cats (Or any other table that is referenced)
Column 'id' exists before you create the foreign key. (Or any other column that is referenced)
A quite bulletproof solution for me is to setup the tables with a first migration eg
public function up()
{
Schema::create('users', function(Blueprint $table)
{
$table->increments('id');
$table->timestamps();
$table->string('cats_id');
});
//and
Schema::create('cats', function(Blueprint $table)
{
$table->increments('id');
$table->timestamps();
$table->string('cat_name');
});
}
in one migration file and then I create another migration file that runs in the end and creates all the foreign keys for all migrations that were running before:
public function up()
{
Schema::table('cats', function(Blueprint $table)
{
$table->foreign('id')->references('cats_id')->on('users');
});
}
You can also choose what should happen to your cats table on update or delete of a user by adding eg
->onUpdate('CASCADE')->onDelete('CASCADE');
to the $table->... line
You will have to run the migration for cats table and create that table before you can associate it with users table.
Foreign key relation will be helpful when you are required to do cascade delete or update. Also an insert like the following will be easier for you with the cats relationship set.
$user = User::find(1);
$cats = array(
new Cat(array('name' => 'Kitty')),
new Cat(array('name' => 'Lily')),
);
$user->cats()->save($cats);
When specifying a relationship on User Model the Cat model also needs to exist.
In migration
Users
$table->foreign('cats_id')->references('id')->on('cats');
Cats
$table->foreign('user_id')->references('id')->on('users');
Now you force integrity on database level.
Migrate
run the migration using php artisan migrate
Next step is to add the integrity on you Model
Model
User.php
public function cats()
{
return $this->hasMany('Cats');
}
Cat.php
public function user()
{
return $this->belongsTo('User');
}

Categories