In raw MySQL it's easy to disable foreign key checks temporarily while you're doing migrations etc.
SET foreign_key_checks = 0;
My team uses Tortoise ORM and we need to replicate that functionality. How can we do that?
Google and Stack Overflow searches have yielded nothing.
Migrations generated by Tortoise ORM fail when a FK constraint needs to be ignored.
I've just deployed my app to DigitalOcean using (Managed Database) and I'm getting the following error when calling php artisan migrate
SQLSTATE[HY000]: General error: 3750 Unable to create or change a
table without a primary key, when the system variable 'sql_require_primary_key'
is set. Add a primary key to the table or unset this variable to avoid
this message. Note that tables without a primary key can cause performance
problems in row-based replication, so please consult your DBA before changing
this setting. (SQL: create table `sessions` (`id` varchar(255) not null,
`user_id` bigint unsigned null, `ip_address` varchar(45) null,
`user_agent` text null, `payload` text not null, `last_activity` int not null)
default character set utf8mb4 collate 'utf8mb4_unicode_ci')
It appears that Laravel Migrations doesn't work when mysql var sql_require_primary_key is set to true.
Do you have any solutions for that?
From March 2022, you can now configure your MYSQL and other database by making a request to digital ocean APIs.
Here's the reference: https://docs.digitalocean.com/products/databases/mysql/#4-march-2022
STEPS TO FIX THE ISSUE:
Step - 1: Create AUTH token to access digital ocean APIs. https://cloud.digitalocean.com/account/api/tokens
STEP - 2: Get the database cluster id by hitting the GET request to the below URL with bearer token that you have just generated above.
URL: https://api.digitalocean.com/v2/databases
Step - 3: Hit the below URL with PATCH request along with the bearer token and payload.
URL: https://api.digitalocean.com/v2/databases/{YOUR_DATABASE_CLUSER_ID}/config
payload: {"config": { "sql_require_primary_key": false }}
That's all. It worked flawlessly.
For more information, please refer to API DOCS:
https://docs.digitalocean.com/products/databases/mysql/#latest-updates
I was trying to fix this problem with an import to DO Managed MySQL using a mysqldump file from a WordPress installation. I found adding this to the top of the file did work for my import.
SET #ORIG_SQL_REQUIRE_PRIMARY_KEY = ##SQL_REQUIRE_PRIMARY_KEY;
SET SQL_REQUIRE_PRIMARY_KEY = 0;
I then imported using JetBrains DataGrip and it worked without error.
Add in your first migration:
\Illuminate\Support\Facades\DB::statement('SET SESSION sql_require_primary_key=0');
Inside: Schema::create() function.
Just add set sql_require_primary_key = off
Like this
to your SQL file.
One neat solution is defined here. The solution is to add listeners to migrate scripts and turn sql_require_primary_key on and off before and after executing a migration. This solution solve the problem where one is unable modify migrations script such as when they are from a library or a framework like Voyager.
<?php
namespace App\Providers;
use Illuminate\Database\Events\MigrationsStarted;
use Illuminate\Database\Events\MigrationsEnded;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider {
/**
* Register any application services.
*
* #return void
*/
public function register() {
// check this one here https://github.com/laravel/framework/issues/33238#issuecomment-897063577
Event::listen(MigrationsStarted::class, function (){
if (config('databases.allow_disabled_pk')) {
DB::statement('SET SESSION sql_require_primary_key=0');
}
});
Event::listen(MigrationsEnded::class, function (){
if (config('databases.allow_disabled_pk')) {
DB::statement('SET SESSION sql_require_primary_key=1');
}
});
}
// rest of the class
}
For bigger sql file, can with this command (nano editor can open in 1 week if your file size is <8GB, lol):
First :
sed -i '1i SET SQL_REQUIRE_PRIMARY_KEY = 0;' db.sql
Second :
sed -i '1i SET #ORIG_SQL_REQUIRE_PRIMARY_KEY = ##SQL_REQUIRE_PRIMARY_KEY;' db.sql
According to the MySQL documentation purpose of this system variable is
to avoid replication performance issues: "Enabling this variable helps avoid performance problems in row-based replication that can occur when tables have no primary key."
IMHO, there are two possible options to consider for your problem;
Add primary key to this and every table in your migration, including temporary tables. This one is better and i think more convenient way to do it since there is no drawback to have primary key for each table.
Whether statements that create new tables or alter the structure of existing tables enforce the requirement that tables have a primary key.
Change your provider because according to here "We support only MySQL v8."
Also here is the bug report
I contacted DigitalOcean via a ticket to ask if they want to disable the requirement and they did the next day :)
So you can just ask them
Thanks for getting in touch with us!
I understand you will like to disable the primary requirement on your managed database. The primary requirement for your managed database ****** has been disabled
Unfortunately, we can't change the sql_require_primary_key value in the digital ocean MySQL database. instead, you can set the id to the primary key just by adding primary()
When enabled, sql_require_primary_key has these effects:
Attempts to create a new table with no primary key fail with an error. This includes CREATE TABLE ... LIKE. It also includes CREATE TABLE ... SELECT, unless the CREATE TABLE part includes a primary key definition.
Attempts to drop the primary key from an existing table fail with an error, with the exception that dropping the primary key and adding a primary key in the same ALTER TABLE statement is permitted.
Dropping the primary key fails even if the table also contains a UNIQUE NOT NULL index.
Attempts to import a table with no primary key fail with an error.
Default value is OFF , but in your case you need to set OFF from ON
IMPORTANT LINK
HOW TO SET
If you're importing in some SQL client, just run this query on that particular database before importing.
set sql_require_primary_key = off
Works all good for DO managed Mysql Database. Cheers!
add this line to your migration file.
$table->increments('aid');
I need to update an existing Laravel application by migrating and seeding the database.
I have a table like the following:
items
id
name
And I want to edit the database to look like:
items
id
name
type_id (new column)
types (new table)
id
name
With type_id being a not-null foreign key to the types table.
The types table will be seeded with a Laravel seeder in a following operation. This seeder will be called after each application update and truncate/reinsert some "static" data that only change with updates of the application. It is configured in a way like Laravel : Migrations & Seeding for production data for the local/production differences
Everything runs fine when starting from scratch on local database. But on the production database, there are already many records. As it is a not-null key, the migration fails when pushing to this database (actually, a copy of that database for testing)
As a migrating solution, I'd like to add the first type record to every existing item, but I cannot set the foreign key during the migration, as the items table is empty at this stage, and I cannot leave it empty until the seeding, as the migration don't pass.
There are some things I think to:
Disable the foreign key checks on the database during the whole update, but I'd prefer a solution that allows me to simply push my repository to the server and start my automated deployment script (which essentially call artisan migrate followed by artisan db:seed).
Call the seeder from the migration just after the creation of the types table, but I'm not sure that is a good practice
What should I do ?
Edit: Here's my working migration code using #lukasgeiter answer:
public function up()
{
DB::statement('SET FOREIGN_KEY_CHECKS = 0');
Schema::table('items', function(Blueprint $table)
{
$table->integer('type_id')->unsigned()->index()->after('name');
});
DB::update('update items set type_id = 1');
Schema::table('items', function(Blueprint $table)
{
$table->foreign('type_id')->references('id')->on('types');
// Here I do other stuff to this table
});
DB::statement('SET FOREIGN_KEY_CHECKS = 1');
}
You can just disable foreign key checks inside the migration by using DB::statement and SQL.
DB::statement('SET FOREIGN_KEY_CHECKS = 0');
// add column
DB::statement('SET FOREIGN_KEY_CHECKS = 1');
I have a closed-source upgrade application which migrates my database from an old format to a new format (creates new tables and migrates data from the old to new tables).
The application crashes with a MySQLIntegrityConstraintViolationException. It doesn't give me the name of the table with the primary key violation or the contents of the broken SQL query.
Is there any MySQL server option that I can switch to give me more troubleshooting information? Maybe the text of the failed query or the name of the primary key constraint which is violated?
You can enable the general log file: http://dev.mysql.com/doc/refman/5.1/en/query-log.html . This way it might be possible to see at which point the server stops processing the queries.
You also can run the MySQL command show processlist to see what queries are being processed at that time.
Also have a look into all other application specific error logs.
A first try could be to disable foreign key checks during migration:
SET foreign_key_checks = 0;
A first guess would be, that the old server supported 0 as Primary Key values, whilst the new one does not.
I am trying to use Microsoft Sync Framework for syncing 2 SQL Server 2005 database (server and client). There are multiple tables in the database with lots of foreign key relation between them. I am using SyncOrchestrator to synchronize the two databases.
string clientConnectionString = "<connection string>";
string serverConnectionString = "<connection string>";
SqlSyncProvider localProvider
= ConfigureClientProvider(clientConnectionString);
SqlSyncProvider remoteProvider
= ConfigureServerProvider(serverConnectionString);
SyncOrchestrator orchestrator = new SyncOrchestrator();
orchestrator.LocalProvider = localProvider;
orchestrator.RemoteProvider = remoteProvider;
orchestrator.Direction = SyncDirectionOrder.Download;
In the function ConfigureClientProvider and ConfigureServerProvider I am initializing connection and checking if scope doesn't exits then create it:
public static SqlSyncProvider ConfigureClientSyncProvider()
{
SqlSyncProvider provider = new SqlSyncProvider();
provider.Connection = new SqlConnection(Configs.ConnectionString);
DbSyncScopeDescription scopeDesc = new DbSyncScopeDescription("Test1");
SqlSyncScopeProvisioning serverConfig = new SqlSyncScopeProvisioning();
if (!serverConfig.ScopeExists("Test1", (System.Data.SqlClient.SqlConnection)provider.Connection))
{
scopeDesc.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable
("Employees", (SqlConnection)provider.Connection));
scopeDesc.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable
("Profiles", (SqlConnection)provider.Connection));
scopeDesc.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable
("Department", (SqlConnection)provider.Connection));
serverConfig.PopulateFromScopeDescription(scopeDesc);
serverConfig.SetCreateTableDefault(DbSyncCreationOption.Skip);
serverConfig.Apply((System.Data.SqlClient.SqlConnection)provider.Connection);
}
return provider;
}
Now when I try to run sync its works fine for updated data but I got foreign key issues while there are any inserts or deletes in the database. e.g.
The INSERT statement conflicted with
the FOREIGN KEY constraint
"FK_Employees_Departments". The
conflict occurred in database
"Sync_Client", table
"dbo.Departments", column
'DepartmentID'.
If I do some change in order of tables then I am able to resolve one case of another case arises because of deletion.
The DELETE statement conflicted with
the REFERENCE constraint
"FK_Employees_Departments". The
conflict occurred in database
"Sync_Client", table "dbo.Employees",
column 'DepartmentID'.
Does anyone have any idea how this can be fixed. What I think the sync framework is not able to property executing changes in correct order. This order depending on several factor like foreign key relations, type of command e.g. insert, update etc. I am really stuck here. Early help will be appreciated.
This is an old question now, but since there's no real answer:
Sync requires you to list tables in each scope in insert order, so that all Foreign Key parents are in place before any Foreign Key children are inserted. Sync will automatically reverse that order on delete.
This is all fine and dandy, but if you have a database where for whatever reason the data in your parent or child tables is stored on different servers based on some independent piece of information, so that the parent and child might have different sync rules, you've overstepped any automatic processing that's available.
In this case, where the normal sync filters are built against the primary key information in your BASE tables, you will need to force the filters to use the primary key information in the TRACKING tables instead. There is now some content about this on social.msdn.microsoft.com.