I am building something that allows users to upload their graphical work and other users can comments on the projects and like other projects.
Now when a user wants to delete their own project it works but as soon as the project has comments or likes I get this error:
Integrity constraint violation: 1451
Cannot delete or update a parent row: a foreign key constraint fails
(`scotchbox`.`comments`, CONSTRAINT `comments_on_projects_foreign` FOREIGN KEY (`on_projects`)
REFERENCES `projects` (`id`)) (SQL: delete from `projects`
where `id` = 31 and `user_id` = 32)
I assume this can be resolved by deleting the comments from the comments table and the likes from the likes table aswell? but I honestly have no idea how to fix this issue with the foreign keys.
I think I need a way to delete the comments and likes of the project before deleting the project itself. Is this possible from the destroy function of my ProjectsController?
This is my destroy function for deleting the projects:
public function destroy($id)
{
$input = Request::all();
Project::whereId($id)->whereUserId(Auth::user()->id)->delete();
return redirect('projects/');
}
When you have a foreign key, you can choose the behavior of deletion.
You have: Users, Projects
User has many Projects
so that means in the Projects schema you will have something similar to this
Schema::create('projects', function(Blueprint $table){
// table fields
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
});
In this case, you have established a relation without saying "how to behave" if a deletion occurs on the parent (User), that means if you attempt to delete the user, the query exception will be thrown to protect you.
So, if this is the case, you will have to find all the children (Projects) of that parent (User), and delete them before you are able to delete the Parent.
the 2nd solution would be adding onDelete() behavior:
Schema::create('projects', function(Blueprint $table){
// table fields
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
This means, if you delete the Parent (User) it will automatically find all of the children (Projects) and delete them one by one for you.
Finally, please note that i am using Parent Children analogy in order to clarify the situation, where this analogy only fits in the One to Many relations.
Please avoid using the analogy when you are surrounded by Databasists to protect yourself from further consequences.
The user you try to delete commented on a project. Delete his comments before deleting the user. Or there is a comment on the project you try to delete.
Fixed it by adding onDelete('cascade') to my migrations like this:
Comments migration:
$table->foreign('on_projects')->references('id')->on('projects')->onDelete('cascade');
Likes migration:
$table->foreign('project_id')->references('id')->on('projects')->onDelete('cascade');
Related
I have seen many people write migrations without defining foreign key constraints including jeffrey way in his videos. For example,
Schema::create('post',function(Blueprint $table){
$table->id();
$table->integer('user_id')->index();
$table->text('body');
//
});
Here, there is no foreign key constraint defined like the following
$table->foreign('user_id')->references('id')->on('users');
I always define foreign key because that's how you maintain the relationships and integrity between tables. But I have seen many videos where they do not define the foreign key. Is there any specific reason behind it?
Foreign key constraints make your database consistent. I don't know any another way to do something like cascading. You should read about this too. Consider a scenario where you delete the parent element and child element is just sitting there in some related table. huh! Now that can break your app.
PS: It's not necessary but SHOULD be done.
It's not necessary but we should index everything we use on where(). So yes, you should cretae foreign keys, this way you create indexes and link the tables.
The only reasons to not use these keys are if you don't need consistency in your database or you are sure that your framework/code is not prone to these referential errors. But as seen in the videos, the foreign keys do not have to be defined to have functioning relations in your laravel app.
I am making my table like this...
Schema::create('matched_merchants', function (Blueprint $table)
{
$table->increments('id')->unsigned();
$table->integer('merchant_id')->unsigned();
$table->integer('offer_id')->unsigned();
$table->foreign('merchant_id')->references('id')->on('merchants')->onUpdate('cascade')->onDelete('restrict');
$table->foreign('offer_id')->references('id')->on('offers')->onUpdate('cascade')->onDelete('restrict');
});
Im adding 2 foreign keys both have onUpdate and onDelete constraints but only the update constraint gets added.
If i delete the onUpdate, it will correctly add the onDelete constraint.
I cannot add them separately because i get the error of duplicate key.
I could add them manually with a raw sql statement but if theres a right way to do it id rather do that.
For some reason, if you set the columns as nullable(), Laravel sets the foreign keys correctly.
That said, I can see that causing other problems, so I recommend doing the raw SQL statement.
I'm trying to create a login/register system for a project using laravel, and since it's my first time, I've been running into a lot of troubles, so I'd ask to please forgive me for any extremely dumb mistakes I've made.
I've already succesfully added a new custom field to the default registration screen, but in my modified users table, I also have two foreign keys referencing other tables ('gameInfo_id' refers to the 'gameInfo' table, and 'role_id' refers to the 'roles' table)
This is the error I'm getting:
Does this mean I have to find a way for the foreign key to be filled in automatically? If so, how would I go about doing this?
I've done some googling and found that this usually seems to be issue, but I've never found a clear solution.
Thank you!
Here's my migrations in the users table:
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('firstName');
$table->string('lastName');
$table->string('email')->unique;
$table->string('password');
$table->integer('gameInfo_id')->unsigned();
$table->integer('role_id')->unsigned();
$table->timestamps();
});
Schema::table('users', function($table) {
$table->foreign('gameInfo_id')->references('id')->on('gameInfo');
$table->foreign('role_id')->references('id')->on('roles');
});
gameInfo is a table of scores that the user would achieve in a game we're also making. What I'm trying to make happen is, when a new user registers an account, it creates a new row in gameInfo, to which the gameInfo_id foreign key would refer. The columns of this newly created row could be set to 0 by default if it helps
I would do it the other way around.
I would reference the user on the gameInfo table with a user_id column.
that way, the user hasMany gameInfo, and a gameInfo belongs to a user. Since the Game info isn't created before the user is created, and has played a game.
Does that make sense?
If the users table already contains datasets, where some of them don't have existing gameInfo_id or role_id, you can't add an foreign key constraint to the table.
The table must be in an valid state, before you add an foreign key constraint.
That means: Adding an new foreign key constraint to an existing field is not the best idea. Doing it anyway, you have to fix the integrity before.
If your still on an development environment, the best way to fix this would be to start all over again with migrate:refresh.
If the system runs in production with users, you have to fix all users with invalid or unset gameInfo_id and role_id. If you have just a few users, you could do this by hand. If you have many users, you could do some magic inside the migration script (iterate over all users and add missing references, before you add fk constraints).
Since the ->nullable() didn't seem te be recognized by laravel, I instead decided to give each column in gameInfo a default value of 0, which works just fine for me as well.
On the other hand, reversing the FK relationship between users and gameInfo also worked, so my problem's been resolved!
Thank you all very much for your answers, every contribution is appreciated greatly!
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
I am very new in laravel.I am doing a project where user first of all sign up and his information will store in a User table.then he or she sign in to the website and the user will provide another form for registration as a Blood donner. This imformation will store another table namely blooddonners table.so i want to make a foreign key in blooddonner table.The foreingn key will be the id from the user table.Thats why i have created a migration for blooddonner table like that,
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateBlooddonnerTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('blooddonners', function(Blueprint $table)
{
$table->increments('id');
$table->unsignedInteger('donner_id');
$table->foreign('donner_id')->references('id')->on('users')->onDelete('cascade')->onUpdate('cascade');
$table->string('donner_name');
$table->string('email')->unique();
$table->string('blood_group');
$table->string('phone_number')->unique();
$table->string('location');
$table->date('date_of_birth');
$table->date('last_date_of_donation');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('blooddonners');
}
}
but after submitting the the form,i am facing the following error,
Illuminate \ Database \ QueryException
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`needa`.`blooddonners`, CONSTRAINT `blooddonners_donner_id_foreign` FOREIGN KEY (`donner_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE) (SQL: insert into `blooddonners` (`date_of_birth`, `blood_group`, `location`, `email`, `phone_number`, `last_date_of_donation`, `updated_at`, `created_at`) values (2014-08-06, A-, SHERPUR, raihn_cse#yahoo.com, 01796580404, 2014-08- 20, 2014-08-10 19:42:38, 2014-08-10 19:42:38))
though i am very new in Laravel,so i have question that,the way i have set foreign in my migration file ,is it the rigth way to set foreign key ?, cause the error is related to that foreign key.
There's nothing wrong with the way you're setting up foreign keys. Proof of that is that MySQL is actually stopping you from inserting an entry which violates the foreign key you've told it to enforce. The problem is that you're trying to add a blood donor entry without specifying which user it is related to. You have two options, then:
In the query you are using to add the new blood donor, specify the related user's id;
Even though donor_id is the foreign key, it can be nullable if that's what you want, though you need to tell Laravel / MySQL that.
Here's how to define a nullable column:
$table->unsignedInteger('donor_id')->nullable();
I've taken the liberty of correcting your spelling: blood donner > blood donor. Proper spelling helps code readability, too ;)
Edit
If you want a suggestion on how you can improve your database design in order to make good use of foreign keys, here's how I'd approach it:
First thing: I'd only have a secondary blood_donors table if not every user was a blood donor. If 100% of your users are blood donors, don't over-complicate things: use only one table and add more columns. Otherwise, read on.
My users table would probably have all columns that relate to general personal information:
name
email
phone number (unique on users)
location
date of birth
After that I can just "link" the users table and the blood_donors table via foreign keys so I don't have to repeat myself. All I need to know is which user corresponds to which blood donor, and all I need to accomplish that is an id. That way, when I do a query on the database, whether it's on the blood_donors or users table originally, I can easily join both tables together and have all the data at once, without having it repeated in two different places.
So, going back to your migration, this would now suffice:
Schema::create('blooddonners', function(Blueprint $table)
{
$table->increments('id');
$table->unsignedInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade')->onUpdate('cascade');
$table->string('blood_group');
$table->date('last_date_of_donation');
$table->timestamps();
});
i.e. you don't need a "donor name" in your blood_donors table, because you already have it recorded on your users table, and they are the same person after all. You should have columns which are pertinent only in the context of donating blood.
You can then access all this data with a query like this (assuming you already have your models set up):
User::join('blood_donors', 'users.id', '=', 'blood_donors.user_id')->get();
And you'd have an object with both tables' columns at once. Just be mindful that columns with the exact same name will override each other in your final object, so if you want to reliably access both ids within that object, you'd better specify aliases on the select portion of the query. You can even change the column names if you have to. In Laravel you can do it like this:
User::select('users.*', 'users.name as donor_name', 'blood_donors.id as donor_id')
->join('blood_donors', 'users.id', '=', 'blood_donors.user_id')
->get();
Take a look at the Eloquent documentation on relationships to see how you can take your database designs further and still maintain clean, readable code.