Add foreign key constraints in Laravel migration - php

I know a lot of people asked the same question many times but it seems as if I am not able to make the same solutions work for me.
I am not able to set foreign key for the related tables for which the up() has been given below:
//Migrate 1 Starts
public function up()
{
Schema::create("UserTable", function($table){
$table->tinyInteger("ApplicationID");
$table->bigInteger("UserID");
$table->string("UserName")->unique();
$table->timestamps();
});
}
//Migrate 1 Ends
//Migrate 2 Starts
public function up()
{
Schema::create("Membership", function($table){
$table->tinyInteger("ApplicationID");
$table->bigInteger("UserID");
$table->string("Password");
}
}
//Migrate 2 Ends
//Migrate 3 Starts: This has the latest timestamp, so it runs after all tables are created
public function up()
{
Schema::table('UserTable', function($table) {
$table->primary("UserID");
$table->foreign("UserID")->references("UserID")->on("Membership");
});
Schema::table('Membership', function($table) {
$table->primary("UserID");
$table->foreign("UserID")->references("UserID")->on("UserTable");
});
}
//Migrate 3 Ends
The error I am getting is SQLSTATE[HY000]: General rror: 1215 Cannot add foreign key constraint (SQL: alter table 'Membership' add constraint membership_userid_foreign foreign key ('UserID') references 'UserTable' ('UserID'))

The problem was that I was setting up primary key at the time of setting up foreign key. This was causing problem.
So setting up of primary columns must be done while creating the tables, while foreign keys must be added once all the related tables have been created.
I guess its better that we create a create_associations migration file after all the tables have been created so that this migration has the latest timestamp, and by the time this file is executed, all the tables are present in the database.

Related

Laravel Migration create foreign key using foreignIdFor with specific data type?

So I've been trying to write a migration that creates a data table question_display_formats using tiny increments as you see below.
And then, adding new Foreign Key column to existing questions table, trying to use the foreignIdFor method as a shortcut that'd look nice
public function up()
{
Schema::create('question_display_formats', function (Blueprint $table) {
$table->tinyIncrements('id');
$table->string('format');
});
Schema::table('questions', function (Blueprint $table) {
$table->foreignIdFor(QuestionDisplayFormat::class)
->nullable(true)
->after('question_type_id')
->constrained();
});
}
Turns out, this errors out with
General error: 1215 Cannot add foreign key constraint
Which turns out because the foreignIdFor users a different data type (confirmed by manually matching them and running the erroring out SQL alter table statement).
I googled, read and tried to adjust by doing:
$table->mediumIncrements('question_display_format_id'); before the foreignIdFor line, which leads to error
SQLSTATE[42S21]: Column already exists: 1060 Duplicate column name
'question_display_format_id' (SQL: alter table questions add
question_display_format_id mediumint un signed not null
auto_increment primary key, add question_display_format_id bigint
unsigned null after question_type_id)
Is there a way to use foreignIdFor with the matching column size? or am I supposed to fall back on the classic way of first creating the column explicitly, then doing like $table->foreign('question_display_format_id')->references('id')->on('question_display_formats'); which I don't like because its very verbose and doesn't look good?
On the other hand, this is a one time used script.. lol would've been faster to just do it the old way! but I am curious to see how to do it right :)

Laravel Migrate creating duplicate foreign key names

Schema::create('a', function(Blueprint $table) {
$table->bigInteger('id');
$table->primary('id');
});
Schema::create('b', function(Blueprint $table) {
$table->bigInteger('id');
$table->bigInteger('a_id');
$table->foreign('a_id')->references('id')->on('a');
});
Schema::create('c', function(Blueprint $table) {
$table->bigInteger('id');
$table->bigInteger('a_id');
$table->foreign('a_id')->references('id')->on('a');
});
Running this with php artisan migrate on this gives me a
ORA-02264: name already used by an existing constraint.
It seems that migrate creates a constraint on b called A_ID_PK, then it tries to create a constrain on c called A_ID_PK and errors since there are 2 A_ID_PK constraints on the A.id. Am I correct, and if so is there a solution?
From the error utility, ORA-02264 error means ORA-02264: Name already used by an existing constraint.
And the definition is that specified constraint name has to be unique. So the solution is specify a unique constraint name for the constraint.
Problem and workaround
Not sure but the problem is that while the table may have not been created, the constraint_name might be exists in the dba_constraints view. You can check this like:
select
table_name
from
dba_constraints
where constraint_name = upper ('A_ID_PK');
If you do not have already used this constraint_name for other table.
Your solution is either of the below:
Use another constraint name, that unique to the table.
Make sure that this constraint name exists for a table.

Laravel - 1215 Cannot add foreign key constraint

I try to add a foreign key constraint in migrations. For some reason it does work when I set it to nullable, but it doesn't work when I make it not nullable. Why does this happen and how can I solve this?
This does work:
Schema::create('role_user', function (Blueprint $table){
$table->increments('id');
$table->integer('role_id')->unsigned()->index()->nullable();
$table->foreign('role_id')->references('id')->on('roles')->onDelete('set null');
$table->integer('user_id')->unsigned()->index()->nullable();
$table->foreign('user_id')->references('id')->on('users')->onDelete('set null');
$table->timestamps();
});
This throws the exception:
Schema::create('role_user', function (Blueprint $table){
$table->increments('id');
$table->integer('role_id')->unsigned()->index();
$table->foreign('role_id')->references('id')->on('roles')->onDelete('set null');
$table->integer('user_id')->unsigned()->index()->nullable();
$table->foreign('user_id')->references('id')->on('users')->onDelete('set null');
$table->timestamps();
});
Both the role and user tables already excist before making these constraints. I want them to be not nullable (so they must be filled). The error:
SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint (SQL: alter table role_user add constraint role_user_role_id_foreign foreign key (role_id) references roles (id) on delete set null)
The migrations happen in the order that you specify in the filename. Maybe your roles table hasn't been created by the time this migration is run and your DB complains about trying to reference a field in a (yet) non-existent table?
For example: 2016_03_27_0000_first will be executed before 2016_03_28_0000_second
UPDATE: Added solution.
I noticed that you have "onDelete('set null')" for the field that you are trying to set as non-nullable. That would also cause a problem if the role was deleted, since it would then try to set the value to null.
You should set both foreign keys to:
->onDelete('cascade')
This way if the user or the role get deleted, any associations related to them would also get deleted automatically and not simply set to null or left hanging around.
Cheers

Laravel 5.2 foreign key errors

I have created two migrations with the Jeffrey Way generators for Laravel 5. Namely: php artisan make:migrate:schema create_roles_table --schema='name:string, description:text' and php artisan make:migrate:pivot user role.
Now, my MySQL database is defaulted to InnoDB, which I've read should be. I also moved the foreign key setup to Schema::table() instead of Schema::create('role_user'). There shouldn't be anything wrong with my migrations, yet they error out with: General error: 1215 Cannot add foreign key constraint (SQL: alter table role_user add constraint role_user_user_id_foreign foreign key (user_id) references user (id) on delete cascade).
Schema::create('role_user', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->integer('role_id')->unsigned()->index();
$table->integer('user_id')->unsigned()->index();
$table->primary(['role_id', 'user_id']);
});
Schema::table('role_user', function(Blueprint $table){
$table->foreign('user_id')->references('id')->on('user')->onDelete('cascade');
$table->foreign('role_id')->references('id')->on('role')->onDelete('cascade');
});
I have called $table->engine = 'InnoDB'; in every migration. Also have I set all id columns to unsigned, even though they were like that already. I am clueless, who helps me out..
Check to see if you have already migrated the tables users and roles. Otherwise you will not be able to create a foreign key. Check your migration order as well. If you are migrating this one before the users and roles it will fail.
Well, apparently this was a huge typo. user instead of users, for example. I had hoped Laravel would get that right, but unfortunately Laravel and I as well didn't.
This might be related to your SQL engine, check your engine (mariadb, mysql, ...)
And then read the documentation from your engine regarding foreign keys.
Quick solution
Remove the onDelete('cascade') and run the migration.
You can add it manually from phpMyAdmin later on

Laravel 4: Migration - Schema::table - Text column automatically creates primary unique index

I am creating a migration in Laravel with the following function:
public function up()
{
Schema::create('translate_item', function(Blueprint $table)
{
$table->increments('id');
$table->integer('lesson_id');
$table->text('lang_1');
$table->text('lang_2');
$table->timestamps();
});
}
The above creates the text fields as primary unique index as shown below:
Can anyone tell why this is happenning and how to create text fields without making it primary index?
In fact they aren't created as primary key nor with unique index.
It maybe look like it. The fields are greyed out, because that's how phpMyAdmin displays columns you can't make primary key or unique.
No need to worry. text() does nothing you wouldn't expect.

Categories