cannot add foreign key constraint Laravel 5.1 - laravel

I first created all the tables without their foreign keys, I then added the foreign keys for each table, starting with the first table, i got this error:
SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint (SQL
: alter table `accounts` add constraint accounts_client_id_foreign foreign
key (`client_id`) references `clients` (`id`))
Here's my code:
public function up()
{
Schema::create('accounts', function(Blueprint $table)
{
$table->engine = 'InnoDB';
$table->bigInteger('id');
$table->integer('client_id')->unsigned();
$table->foreign('client_id')->references('id')->on('clients');
$table->integer('emp_id')->unsigned();
$table->foreign('emp_id')->references('id')->on('employees');
$table->string('type');
$table->timestamps();
});
}
I tried without $table->engine='innoDB'; but same error
Plus, i tried to separate the foreign keys:
Schema::table('accounts', function($table) {
$table->foreign('client_id')->references('id')->on('clients');
$table->foreign('emp_id')->references('id')->on('employees');
});
I got this error:
Base table or view already exists: 1050 Table 'accounts' already exists
So when I deleted and re-migrate i get the first error
So whats happening?

I've got same error, it feels like bug to me. What I did is created different migrations for foreign keys. So, first you create table with fields, then (in next by date migration) you add foreign keys.
Then I rolled back all migrations and reruned them with php artisan migrate. It worked for me, I hope it'll also work for you.

I foresee you created the related table("clients") specifying the primary key/id as this
$table->bigInteger('id');
or
$table->integer('id');
which will cause problem in the sense that your foreign key constraint
is being specified as
$table->integer('client_id')->unsigned();
whiles the primary key/id does not have the unsigned() constraint assigned to it.
So change the primary key of the related table to
$table->bigInteger('id')->unsigned();
or
$table->integer('id')->unsigned();
And if you are using bigInteger for the primary key try and make the foerign key also bigInteger. Don't forget to use unsigned() for both (the primary key and the foreign key).

Related

Laravel migration mix up with person/people table names

For some reason Laravel is getting mixed up pluralizing person/persons some reason it assumes my table is people.
I know how to get around this without manually specify the table name inside the $table->foreignId('person_id')->constrained('persons') but I wanted to know why it happens? And which tables names to avoid/watch out for.
Can't create table
person_logs (errno: 150 "Foreign key constraint is incorrectly
formed") (SQL: alter table person_logs add constraint
person_logs_person_id_foreign foreign key (person_id) references
people (id))
Schema::create('persons', function (Blueprint $table) {
$table->id('id');
$table->string('firstname');
$table->string('lastname');
});
Schema::create('person_logs', function (Blueprint $table) {
$table->id('id');
$table->string('example');
$table->foreignId('person_id')->constrained();
});
Down the hood it calls Str::plural() on person as part of person_id, the plural version of this is people. So the correct naming according to the Laravel convention for your persons table is actually people.
So change the table to people or constrained() first parameter is the table name.
$table->foreignId('person_id')->constrained('persons');

laravel6: how to change references of a foreign key with migration

I have tried to change foreign key reference by dropforeign key.I think everything is ok but i get this error:
SQLSTATE[42000]: Syntax error or access violation: 1091 Can't DROP
FOREIGN KEY teacher_schedule_calendars_product_id_foreign; check
that it exists (SQL: alter table teacher_schedule_calendars drop
foreign key teacher_schedule_calendars_product_id_foreign)
How can I solve it?
my migration code is :
Schema::table('teacher_schedule_calendars', function (Blueprint $table) {
$table->dropForeign(['product_id']);
$table->foreign('product_id')->references('id') ->on('courses')->onDelete('cascade');
});
firstly, I ave removed the foreign and then add references. but it did not work.
I'm assuming you created a foreign key on the product_id column in a previous migration and you simply want to renew it or replace it with a foreign key to another table. In this case, what you are attempting to do might be problematic due to the way how migrations work and how individual database grammatics translate the commands.
What you can do to mitigate the issue is splitting the commands into two Schema::table($table) blocks:
Schema::table('teacher_schedule_calendars', function (Blueprint $table) {
$table->dropForeign(['product_id']));
});
Schema::table('teacher_schedule_calendars', function (Blueprint $table) {
$table->foreign('product_id')->references('id')->on('courses')->onDelete('cascade');
});

Dropping sqlite column fails when updating laravel/eloquent model using database manager migration script

I'm having an issue with attempting to run tests in my Laravel application. I have a table structure as follows:
These SQL Queries have been generated by an export script using TablePlus, as I figured it was the easiest way to share the table structure.
After Migration (NOW)
CREATE TABLE `business_system_role_location_type` (
`business_system_role_id` char(36) COLLATE utf8mb4_unicode_ci NOT NULL,
`location_type_id` char(36) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`business_system_role_id`,`location_type_id`),
KEY `business_system_role_loc_type_fk` (`location_type_id`),
CONSTRAINT `business_system_role_loc_type_fk` FOREIGN KEY (`location_type_id`) REFERENCES `location_types` (`id`),
CONSTRAINT `business_system_role_loc_type_role_id_fk` FOREIGN KEY (`business_system_role_id`) REFERENCES `business_system_roles` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
Before Migration
CREATE TABLE `business_system_role_location_type` (
`business_system_role_id` char(36) COLLATE utf8mb4_unicode_ci NOT NULL,
`location_type` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`business_system_role_id`,`location_type`),
CONSTRAINT `business_system_role_loc_type_role_id_fk` FOREIGN KEY (`business_system_role_id`) REFERENCES `business_system_roles` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
So as you can see, I have ran a migration and removed the location_type field and replaced it with a foreign key to a new location_types table. Both the business_system_role_id and location_type are set to UNIQUE PRIMARY KEY.
This all appears to work fine with MySQL but as soon as I attempt to run any of my tests (using SQLite) it stops working and complains:
Illuminate\Database\QueryException : SQLSTATE[23000]: Integrity constraint violation: 19 NOT NULL constraint failed: business_system_role_location_type.location_type (SQL: insert into "business_system_role_location_type" ("business_system_role_id", "location_type_id") values (bb2051c2-1b5c-498d-bbcf-6dd9e20c4803, 38215722-bcba-4cac-8c83-fe867d8d8e65))
Question
Why am i getting a NOT NULL constraint for business_system_role_location_type.location_type when that column no longer exists? I have tried setting location_type to nullable->(true) before the migration, on the assumption it might update some SQLite setting, but this did not work.
I tried adjusting my code so that it performed $model->location_type = 'something' before $model->save(), and that worked... Even though the column does not exist. All references to it have been removed. I don't want to have to live with a workaround here and would like to get to the bottom of the reason for this error.
The Model looks as follows:
class BusinessSystemRoleLocationType extends Model
{
protected $table = 'business_system_role_location_type';
protected $fillable = [
'business_system_role_id',
'location_type_id',
];
public $incrementing = false;
public $timestamps = false;
public function businessSystemRole(): BelongsTo
{
return $this->belongsTo(
BusinessSystemRole::class,
'business_system_role_id',
'id'
);
}
}
Any help here would be greatly appreciated. :)
Edit - Migration
Here is the portion of the migration which deals with this table:
// Add location_type_id field to table
Schema::table('business_system_role_location_type', function (Blueprint $table) {
// Must be nullable until it is populated with data
$table->uuid('location_type_id')
->nullable()
->after('business_system_role_id');
});
// Assign location_type_id value to all entries
BusinessSystemRoleLocationType::all()->each(function ($businessSystemRoleLocationType) {
$locationTypeDataSetIndex = \array_search(
$businessSystemRoleLocationType->location_type,
\array_column($this->locationTypeDataSet, 'existsAs'),
true
);
if ($locationTypeDataSetIndex !== false) {
$newLocationTypeData = $this->locationTypeDataSet[$locationTypeDataSetIndex];
$newLocationType = LocationType::whereSlug($newLocationTypeData['slug'])->get()->first();
} else {
$newLocationType = LocationType::all()->first();
}
$businessSystemRoleLocationType->location_type_id = $newLocationType->id;
$businessSystemRoleLocationType->save();
});
// Adjust primary index and add foreign keys, and drop location_type field from table
Schema::table('business_system_role_location_type', function (Blueprint $table) {
$table->dropForeign('business_system_role_loc_type_role_id_fk');
$table->dropPrimary(['business_system_role_id', 'location_type']);
});
Schema::table('business_system_role_location_type', function (Blueprint $table) {
// ATTEMPT TO SET FIELD TO NULLABLE BEFORE REMOVING IT, MAYBE THIS WILL FIX THE NOT NULL CONSTRAINT ERROR?
$table->string('location_type')->nullable()->change();
});
Schema::table('business_system_role_location_type', function (Blueprint $table) {
$table->foreign('location_type_id', 'business_system_role_loc_type_fk')
->references('id')
->on('location_types');
$table->foreign('business_system_role_id', 'business_system_role_loc_type_role_id_fk')
->references('id')
->on('business_system_roles')
->onDelete('cascade');
// Now set not nullable UUID (Doctrine (change()) does not support UUID type)
$table->string('location_type_id', 36)->change();
$table->primary(['business_system_role_id', 'location_type_id'], 'business_system_role_loc_type_pk');
$table->dropColumn('location_type');
});
Edit 2 - Solution
I am editing here to provide my solution - though I will leave this open as others will most likely provide a better answer.
From what I can understand in order to remove constraints in an SQLite database it is recommended to delete the table and recreate it. (See here: https://stackoverflow.com/a/4007086/9675332). It appears that SQLite saves these constraints somewhere and doesn't actually remove them just because you remove the column. I really did not want to go down this route though, so here is what i did:
Solution 1: I modified my migration to set the field to have a default value before removing it, and this did pass the test (though it then subsequently failed on the UNIQUE constraint so it's not a working solution in my case, but may well work for others!)
Solution 2: Probably what I should have done to begin with actually. I simply renamed the column from location_type to location_type_id and manually set it to char(36). This appears to have updated everything in the background along with it and it now passes the tests.

Foreign key constraint is incorrectly formed with Composite Keys

I have a table "theaters". In which (theater_name,area_name,station) are composite key.And in the table "cubelists" I have columns (thtr_name,area,stn) which are to be referred to (theater_name,area_name,station) of table "theaters".
The problem here is the combination of the columns - (theater_name,area_name,station) in table "theaters" is unique as it is a composite key. But each column separately is not unique.
Then how can I refer these columns from table "cubelists"?
Schema::create('theaters', function (Blueprint $table) {
$table->string('theater_name');
$table->string('area_name');
$table->string('station');
$table->primary(array('theater_name','area_name','station'));
$table->text('address');
$table->bigInteger('phno');
$table->string('contact_person');
});
public function up()
{
//
Schema::create('cubelists', function (Blueprint $table) {
$table->string('mvie_name');
$table->foreign('mvie_name')->references('movie_name')->on('movies');
$table->string('thtr_name');
$table->string('area');
$table->string('stn');
$table->foreign(array('thtr_name','area','stn'))-
>references(array('theater_name','area_name','station'))-
>on('theaters');
$table->primary(array('mvie_name','thtr_name','area','stn'));
$table->string('type');
$table->string('subtype');
$table->date('validity');
$table->string('show');
});
}
If I give the above code I get an error as
Migration table created successfully.
[Illuminate\Database\QueryException]
SQLSTATE[HY000]: General error: 1005 Can't create table `boras_cachii`.`#sql-a10_
112` (errno: 150 "Foreign key constraint is incorrectly formed") (SQL: alter tabl
e `agreements` add constraint agreements_area_name_foreign foreign key (`area_nam
e`) references `cubelists` (`area`))
[PDOException]
SQLSTATE[HY000]: General error: 1005 Can't create table `boras_cachii`.`#sql-a10_
112` (errno: 150 "Foreign key constraint is incorrectly formed")
You must first create the table, then foreign keys.
Schema::create('cubelists', function (Blueprint $table) {
$table->string('mvie_name');
$table->string('area');
$table->string('stn');
$table->primary(array('mvie_name','thtr_name','area','stn'));
$table->string('type');
$table->string('subtype');
$table->date('validity');
$table->string('show');
$table->foreign(array('thtr_name','area','stn'))
->references(array('theater_name','area_name','station'))
->on('theaters');
$table->foreign('mvie_name')
->references('movie_name')
->on('movies');
});
Also theaters table must migrate first since cubelists is referencing it. And make sure that the foreign key column and the referencing column are the same type or length.

Laravel migration fails multiple primary keys

I am trying to create a Migration in Laravel but it fails saying I got multiple primary keys.
public function up()
{
Schema::create('spins', function (Blueprint $table) {
$table->integer('rid', true, true);
$table->bigInteger('pid');
$table->integer('result');
$table->integer('bet');
$table->timestamps();
$table->primary(array('rid', 'pid'));
});
}
The error:
SQLSTATE[42000]: Syntax error or access violation: 1068 Multipleprimary key defined
(SQL: alter table `spins` add primary key `spins_rid_pid_primary` (`rid`, `pid`))
The autoincrement of rid is the problem (second parameter in the line below).
$table->integer('rid', true, true);
If you are using InnoDB as MySQL engine it doesn't allow composite primary keys with an auto increment.
But if you change to the MyISAM engine it would be possible to do so.
Add $table->engine = 'MyISAM'; to your Migration.
Declare the rid field as a normal integer column
Laravel doesn't provide a method to change existing columns so you need to run a raw SQL query: DB::statement('ALTER TABLE spins MODIFY rid INTEGER NOT NULL AUTO_INCREMENT');
public function up()
{
Schema::create('spins', function (Blueprint $table) {
$table->engine = 'MyISAM';
$table->integer('rid')->unsigned();
$table->bigInteger('pid');
$table->integer('result');
$table->integer('bet');
$table->timestamps();
$table->primary(array('rid', 'pid'));
DB::statement('ALTER TABLE spins MODIFY rid INTEGER NOT NULL AUTO_INCREMENT');
});
}
Your primary key makes no sense.
You are adding a composite primary key to an auto incrementing column and another column. The auto incrementing column will already always be unique so you should just have only that be your primary key.
If you need pid to be unique, set rid to your primary key and add a unique key on pid.
Schema::create('spins', function (Blueprint $table) {
$table->increments('rid');
$table->bigInteger('pid');
$table->integer('result');
$table->integer('bet');
$table->timestamps();
$table->unique('pid');
});
If for some reason you do need your primary key to include rid and pid, this seems to work for me.
CREATE TABLE `spins` (
`rid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`pid` BIGINT(20) NOT NULL,
`result` INT(11) NOT NULL,
`bet` INT(11) NOT NULL,
`created_at` TIMESTAMP NOT NULL,
`updated_at` TIMESTAMP NOT NULL,
PRIMARY KEY (`rid`, `pid`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
You can't have multiple primary keys on a single table. You can have a composite primary key, which is a primary key made from two or more columns. Apparently Blueprint does not support creating composite keys, so you'll have to use the query builder if you want to use composite keys.
Otherwise you can just choose pid or rid as your primary key.

Resources