Propaganistas
Propaganistas

Reputation: 1792

Delete related hasManyThrough models

I have a some models related to eachother like this:

Order
  - hasMany(CartItem)
  - hasManyThrough(Product, CartItem)

CartItem
  - belongsTo(Order)
  - hasOne(Product)

Product
  - belongsTo(CartItem)

All of the relationships are verified to be working by calling both the dynamic property and the method form (e.g. $order->products and $order->products() for an Order model)

Now I'd like to delete all products related to a specific order, so I tried this (with order ID = 3):

Order::find(3)->products()->delete()

However this isn't working. For one reason or the other I get the error message stating the joining column could not be found:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'cart_items.order_id' in 'where clause' (SQL: delete from `products` where `cart_items`.`order_id` = 3)  

The raw SQL output (using toSql()) does however include the join...

Anyone knows what's wrong here?

Upvotes: 2

Views: 1361

Answers (1)

Jarek Tkaczyk
Jarek Tkaczyk

Reputation: 81167

Query Builder delete method() works a bit defferently to other methods, thus it mutates the query and there is no join - it simply takes 'wheres' and ommits other parts of the builder. That being said to achieve what you want use one of these:

// This will run delete query for every product
Order::find(3)->products->each(function ($product) {
   $product->delete();
});


// This will run only single query for all of them, which is obviously faster
$productsIds = Order::find(3)->products->modelKeys();
Product::whereIn('id', $productsIds)->delete();

Mind that both methods remove rows from the DB but don't remove models from the Collection:

$order = Order::find(3);
// run deletes
$order->products; // Collection still contains all the models!

Upvotes: 6

Related Questions