Laravel migration from nullable to not null with null data in database - laravel

my code below is working fine. Problem is when i got data in database which is null in user_id field. Migration rollback will not pass successfully. What is good approach to solve this problem?
Should i change every null in column user_id to empty string before i change nullable to false in rollback?
public function up()
{
Schema::table('classes', function (Blueprint $table) {
$table->text('user_id')->nullable()->change();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('classes', function (Blueprint $table) {
$table->text('user_id')->nullable(false)->change();
});
}

This problem has been seem before, I couldn't find other solution than update the values to empty string before changing the column, the database engine will always complaint.
Updated:
You could do this like this and should work:
use Illuminate\Support\Facades\DB;
/*
*
* Some code
*
*/
public function up()
{
DB::table('classes')->whereNull('user_id')->update(['user_id'=>'']);
Schema::table('classes', function (Blueprint $table) {
$table->text('user_id')->nullable()->change();
});
}

Related

Laravel Migration Rollback of Index with Column Change

I'm trying to test a migration rollback after changing a column type and setting the index.
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('attachments', function(Blueprint $table) {
$table->dropIndex('attachment_id');
$table->text('attachment_id')->nullable()->change();
});
}
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::table('attachments', function(Blueprint $table) {
$table->unsignedBigInteger('attachment_id')->nullable()->change();
$table->index('attachment_id');
});
}
The migration runs fine and assigns the index. But when I run the rollback I run into the following error:
SQLSTATE[42000]: Syntax error or access violation: 1170 BLOB/TEXT column 'attachment_id' used in key specification without a key length (SQL: ALTER TABLE attachments CHANGE attachment_id attachment_id TEXT DEFAULT NULL)
This table was originally set up incorrectly (without an index and without the correct column type). I'm trying to update this but I also want to make sure if any issues occur in production due to the change it can be rolled back quickly.
How are you meant to get around this? The index is already meant to be dropped?
I've tried changing the order of operations and also running separate Schema functions. Also tried changing it to a string instead of text with a set length and no luck.
The below doesn't work:
public function down()
{
Schema::table('attachments', function(Blueprint $table) {
$table->dropIndex('attachment_id');
});
Schema::table('attachments', function(Blueprint $table) {
$table->string('attachment_id', 255)->change();
});
}
public function down()
{
Schema::table('attachments', function(Blueprint $table) {
$table->dropIndex('attachment_id');
$table->string('attachment_id', 255)->change();
});
}
public function down()
{
Schema::table('attachments', function(Blueprint $table) {
$table->string('attachment_id', 255)->change();
$table->dropIndex('attachment_id');
});
}
Well apparently I missed something because putting the dropIndex inside an array worked.
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('attachments', function(Blueprint $table) {
$table->dropIndex(['attachment_id']);
});
Schema::table('attachments', function(Blueprint $table) {
$table->string('attachment_id', 255)->change();
});
}
Answer found here:
https://github.com/laravel/framework/issues/20501#issuecomment-321814806
That's because your the name of your index is test_table_user_id_index in this case. That happens in the createIndexName method in Blueprint.php:
$index = strtolower($this->table.''.implode('', $columns).'_'.$type);
When you pass a string as a parameter, the method will not convert it to a name. Only when you pass an array:
protected function dropIndexCommand($command, $type, $index)
{
$columns = [];
// If the given "index" is actually an array of columns, the developer means
// to drop an index merely by specifying the columns involved without the
// conventional name, so we will build the index name from the columns.
if (is_array($index)) {
$index = $this->createIndexName($type, $columns = $index);
}
return $this->indexCommand($command, $columns, $index);
}

: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails in laravel migration

In my migration file , I am adding organization id to the user's table , i tried all of the code below but not solved yet
class AddOrganizationIdToUsersTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
// $table->foreignId('organization_id')->references('id')->on('organizations')->onDelete('cascade');
$table->foreignId('organization_id')->constrained('organizations')->cascadeOnDelete();
// $table->foreign('organization_id')->references('id')->on('organizations')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
//
});
}
I have data on my user's table so it is giving errors while migrating, to solve it I add the field as nullable
$table->foreignId('organization_id')->nullable()->references('id')->on('organizations')->onDelete('cascade');
if you write with foreignId need:
$table->foreignId('organization_id')->constrained('organizations')->cascadeOnDelete();
or just foreign
$table->foreign('organization_id')->references('id')->on('organizations')->onDelete('cascade');
What could be the issue is that this migration is running before the organizations table migration, and when it tries to find it to create the constraint it fails.
What I would suggest is on the AddOrganizationIdToUsersTable :
Schema::table('users', function (Blueprint $table) {
$table->foreignId('organization_id');
});
And on the Organization creation migration:
Schema::table('users', function(Blueprint $table) {
$table->foreign('organization_id')->references('id')->on('organizations');
});
#2 solution:
Move the migration of Organization table to run before your AddOrganizationIdToUsersTable by changing the timestamp on the name of the file

SQLite Expecting a string as Index Column when dropping a column

<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class RemoveConstructionDateToOrdersTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
if (Schema::hasColumn('orders', 'construction_date')) {
Schema::table('orders', function (Blueprint $table) {
$table->dropColumn('construction_date');
});
}
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('orders', function (Blueprint $table) {
$table->date('construction_date');
});
}
}
When I am migrating this laravel migration on a sqlite database, I am getting
the following error.
InvalidArgumentException: Expecting a string as Index Column
I found where the problem is after hours of poking around. Looks like the doctrine/dbal package cannot rename/handle/drop?! SQLite columns that already have an index
So my solution was to NOT make any indexes on columns that get later renamed in the migrations
Of course we do want the indexes to exist in MySQL so here's my solution to it.
Schema::table('comments', function (Blueprint $table) {
$table->string('commentable_type', 100)->nullable()->after('id');
//only add index if the connection is mysql
if(config('DB_CONNECTION') === 'mysql'){
$table->index('commentable_type');
}
});
So later when you try to rename the column and using SQLite it works.

Dropping foreign keys in Laravel migration

I have a problem with dropping some foreign keys from my Laravel application. The problem is when I am trying to rollback the migration:
php artisan migrate:rollback
I don't know why I have errors in the console:
[Illuminate\Database\QueryException]
SQLSTATE[42000]: Syntax error or access violation: 1091 Can't DROP 'role_user_user_id_foreign'; check that column/key exists (SQL: alter table role_user drop foreign key role_user_user_id_foreign)
[Doctrine\DBAL\Driver\PDOException]
SQLSTATE[42000]: Syntax error or access violation: 1091 Can't DROP 'role_user_user_id_foreign'; check that column/key exists
[PDOException]
SQLSTATE[42000]: Syntax error or access violation: 1091 Can't DROP 'role_user_user_id_foreign'; check that column/key exists
Below I'm showing my migration class:
class UpdateRoleUserTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
schema::table('role_user',function(Blueprint $table){
$table->foreign('user_id')->references('id')->on('users');
$table->foreign('role_id')->references('id')->on('roles');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('role_user', function (Blueprint $table) {
$table->dropForeign('role_user_user_id_foreign');
$table->dropForeign('role_user_role_id_foreign');
});
}
}
My table in the database has been created by migration class:
class CreateRoleUserTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('role_user', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->integer('role_id')->unsigned();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('role_user');
}
}
In all of the >4.0 versions of Laravel, it allows placing column names into an array, which it will then resolve on its own. I tried to find accompanying docs, but they seem to have left it out.
In your update migration, try this:
Schema::table('role_user', function (Blueprint $table) {
$table->dropForeign(['user_id']);
$table->dropForeign(['role_id']);
});
I just had this issue and the problem was due to the fact that $table->dropForeign([column_name]); drops the index and not the column itself. The solution is in the down function drop the index in one block and then drop the actual column in a separate block. They have to be dropped in separate blocks because of something to do with not being able to drop the key in the same connection as where the column is being dropped.
So the down function should look like this:
public function down() {
// drop the keys
Schema::table('role_user', function (Blueprint $table) {
$table->dropForeign(['user_id']);
$table->dropForeign(['role_id']);
});
// drop the actual columns
Schema::table('role_user', function (Blueprint $table) {
$table->dropColumn('user_id');
$table->dropColumn('role_id');
});
}
now you can run php artisan migrate to run the up function and php artisan migrate:rollback to run the down command and the error no longer shows.
I have modified your code below.
Add the onDelete() and onUpdate() to your code.
public function up()
{
Schema::table('role_user',function(Blueprint $table) {
$table->foreign('user_id')->references('id')->on('users')->onDelete('CASCADE')->onUpdate('CASCADE');
$table->foreign('role_id')->references('id')->on('roles')->onDelete('CASCADE')->onUpdate('CASCADE');
});
}
public function down() {
Schema::table('role_user', function (Blueprint $table) {
$table->dropForeign(['user_id']);
$table->dropForeign(['role_id']);
});
}
In Laravel 9.x, you do not need to specify a separate deletion of foreign keys.
<?php
use App\Models\Question;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up(): void
{
Schema::create('answers', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(Question::class, 'question_id');
$table->text('correctly');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down(): void
{
Schema::dropIfExists('answers');
}
};

Setting Default Value for Primary Key in Laravel Migration for sqlite

I've created the database migration below. What I'd like to do is create an accounts table with an id as a primary key. However, I don't want the key to autoincrement starting at 1. Rather, I'd like it to autoincrement starting at 800500.
Is there a way to set the default value of a primary key like this?
I'm currently using Laravel v4.2.11 and sqlite v3.8.3.
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateAccountsTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('accounts', function(Blueprint $table)
{
$table->increments('id')->unsigned()->default(800500);
$table->string('name', 100);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('accounts');
}
}
The default method in the schema builder
Declare(s) a default value for a column
If you need the increment to start at a given value take a look at this answer.
You'd add the query to the migration:
public function up()
{
Schema::create('accounts', function(Blueprint $table)
{
$table->increments('id');
$table->string('name', 100);
$table->timestamps();
});
DB::statement("UPDATE SQLITE_SEQUENCE SET seq = 800500 WHERE name = 'accounts'");
}
There is no 'laravel' way to do this.

Resources