laravel eloquent - Use without on nested eager loaded relations
Asked Answered
D

2

7

I'm currently working on laravel framework and I'm stuck with some relations and eager loading issues.

Situation

I have three models A, B and C

I have two relations

  • A has many B
  • B has many C

By default (using the $with attribute in Model) :

  • A doesn't include B
  • B include C

So most of the time I'm using A without B and B with C

And here is how I've set up the relationship methods & eager loading

class A extends Model {
...

  protected $with = [];

  public function bs() {
      return $this->hasMany('App\Models\B');
  }

}

class B extends Model {
...

  protected $with = ['cs'];

  public function cs() {
      return $this->hasMany('App\Models\C');
  }

  public function a() {
      return $this->belongsTo('App\Models\A');
  }
}

class C extends Model {
...

  public function b() {
      return $this->belongsTo('App\Models\B');
  }
}

Problem

For a specific task I'd like to query A with all B and without any C

When I'am using A::query()->with('b') C are loaded by default

So I'am trying to use A::query()->with('b')->without('b.c') But it keep loading B to C relations.

Have you any idea on how to achieve this ?

Thanks for your help !

Disseisin answered 12/2, 2020 at 19:27 Comment(3)
Can you show exactly what your model internals look like - specifically how you've set up the relationship methods?Tag
I updated my postDisseisin
if you are using protected $with = ['cs'] and don't want to load b, then just add without as below public function cs() { return $this->hasMany('App\Models\C')->without('b'); }Celebrated
F
11

The Eloquent\Model has a newQueryWithoutRelationships.

I think you could do the following:

(new A())->newQueryWithoutRelationships()->with(...)

Update after comment

Interesting method without() (did not know about it).

It looks like you could try the following:

A::query()->with(['bs' => function($query) {
    $query->without('c');
}]);
Fredel answered 12/2, 2020 at 19:37 Comment(2)
No it doesn't work... newQueryWithoutRelationships() remove the relations for model A but not for those I add with the with()statement..Disseisin
The updated part of the answer doesn't work for me. using $query->without('c'); still returns cValue
T
0

This is happening because withing B class you've used:

protected $with = ['cs'];

Which will eager load cs() relationship with each query.

Once you've removed it, you should see that

A::query()->with('b')

will only load associated B models, without its corresponding C's.

Tag answered 13/2, 2020 at 17:28 Comment(1)
Yep I know that ! My question is, is there a way to keep my eager loads (because it's the common case for my app) but remove it just for one request ?Disseisin

© 2022 - 2024 — McMap. All rights reserved.