Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

priverop's avatar

Delete a row WITHOUT cascade

Hello,

I have a simple one to many relationships between Part and Presupuesto. A Presupuesto can have many Parts.

When I deleted a Part I also got the Presupuesto deleted, which I don't want. I removed the ->onDelete('cascade') but I have a Integrity constraint violation:

 local.ERROR: SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`bbdd`.`parts`, CONSTRAINT `parts_presupuesto_id_foreign` FOREIGN KEY (`presupuesto_id`) REFERENCES `presupuestos` (`id`)) (SQL: delete from `presupuestos` where `id` = 2) {"exception":"[object] (Illuminate\Database\QueryException(code: 23000): SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`bbdd`.`parts`, CONSTRAINT `parts_presupuesto_id_foreign` FOREIGN KEY (`presupuesto_id`) REFERENCES `presupuestos` (`id`)) (SQL: delete from `presupuestos` where `id` = 2) at /Applications/XAMPP/xamppfiles/htdocs/modifase-v2/vendor/laravel/framework/src/Illuminate/Database/Connection.php:664, PDOException(code: 23000): SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`bbdd`.`parts`, CONSTRAINT `parts_presupuesto_id_foreign` FOREIGN KEY (`presupuesto_id`) REFERENCES `presupuestos` (`id`)) at /.../vendor/laravel/framework/src/Illuminate/Database/Connection.php:483)

PART MIGRATION

public function up()
    {
        Schema::create('parts', function (Blueprint $table) {
            $table->increments('id')->unsigned()->unique();
            $table->string('name');
            $table->integer('presupuesto_id')->unsigned();
            $table->foreign('presupuesto_id')->references('id')->on('presupuestos');
            $table->timestamps();
        });
    }

PART CONTROLLER

public function destroy($id)
    {
      
      $part = Part::find($id)->delete();

      return response()->json($part);
    }

PART MODEL

public function presupuesto(){
    return $this->belongsTo('App\Presupuesto');
  }
protected $fillable = [

        'name', 'presupuesto_id'

    ];

What should I do?

Thanks!

EDIT: I just found the issue. In my AJAX request I wasn't getting the URL:

var form_action = $(element).next().val();
  console.log(form_action); // THIS WAS EMPTY
  $.ajax({
      dataType: 'json',
      type: 'DELETE',
      url: form_action
  }).done(function(data){
      location.reload();
  });

So it seems like the ajax was requesting a DELETE in the current url of the app (presupuesto/1), and it deletes the presupuesto and the part.

0 likes
6 replies
Snapey's avatar

remove the foreign key constraint on that parts table

gregrobson's avatar

That's not going to help with data integrity @Snapey!

If I remember correctly the default action for a constraint if you don't specify onDelete() is NO ACTION or RESTRICT.

@priverop - the onDelete() – and `onUpdate for that matter – have multiple options I'll summarise the the MySQL docs here (most other DB engines are the same FYI): https://dev.mysql.com/doc/refman/5.7/en/create-table-foreign-keys.html#idm140425854845104

Taking the "posts and comments" example. ON UPDATE/DELETE...

  • CASCADE - If the post.idchanges, change the comment.post_id. If the post is deleted, cascade and delete the related comments
  • SET NULL - If you change or delete post.id the records that were related have their comment.post_id set to NULL. In this case deleting a post leaves comments "orphaned". A comment might no belong to any post, but would still exist. [1]
  • NO ACTION / RESTRICT - Mostly the same 90% of the time they are used. Deleting the post isn't allowed until all comments have been removed before you remove the post. [2]

[1] Of course this won't work if the column has a NOT NULL constraint set on it!

[2] RESTRICT is the default for MySQL

At the moment you have

on table `bbdd`.`parts`
CONSTRAINT `parts_presupuesto_id_foreign` FOREIGN KEY (`presupuesto_id`) REFERENCES `presupuestos` (`id`)

If you wanted to keep the bbdd.parts records when deleting the presupuestos your foreign key should be supplied as follows:

$table->foreign('presupuesto_id')->references('id')->on('presupuestos')->onDelete('SET NULL');

Foreign keys are a great way to validate data being added, but also can be very helpful with managing business logic. e.g. if an entry in a package table belonged to a delivery_vehicle - you wouldn't want to delete the package if you removed the delivery_vehicle! In this case SET NULL would be best: then the package is shown as belonging to no delivery vehicle.

Hope that helps.

3 likes
priverop's avatar

@gregrobson Thanks!

But what I want is DELETE PART and keep my Presupuesto.

I don't want to delete a Presupuesto.

And right now if I delete a Part (with onDelete(cascade)) it deletes the Presupuesto!! Shouldn't be like that

gregrobson's avatar

@priverop - looking at your constraint

`bbdd`.`parts`, CONSTRAINT `parts_presupuesto_id_foreign` FOREIGN KEY (`presupuesto_id`) REFERENCES `presupuestos` (`id)

It's set up so that a presupuesto has many parts - deleting the part should have no effect on the part - are there any other key constraints in effect?

priverop's avatar

The app is way bigger but in this relationship there are just this key...

I can't understand why it deletes the "prespuesto"!

If I delete it via PHPMYADMIN it works fine (the presupuesto is still there), but from Laravel it deletes the presupuesto.

EDIT: I just found the issue. In my AJAX request I wasn't getting the URL:

var form_action = $(element).next().val();
  console.log(form_action); // THIS WAS EMPTY
  $.ajax({
      dataType: 'json',
      type: 'DELETE',
      url: form_action
  }).done(function(data){
      location.reload();
  });

So it seems like the ajax was requesting a DELETE in the current url of the app (presupuesto/1), and it deletes the presupuesto and the part.

Thanks!!!

@gregrobson

1 like

Please or to participate in this conversation.