Crud: Eager loading not used in edit

Created on 21 Apr 2017  路  13Comments  路  Source: Laravel-Backpack/CRUD

If you set ->with() related items in CRUD controller, list view eager load them, but edit doesn't, making a lot of additional queries to the database.

I'm on mobile until tonight, maybe someone can confirm, otherwise I can publish more details tomorrow if needed

Most helpful comment

@lloy0076 Not exactly, I used the standard edit view but added a custom field using a custom view: that way I can extend a lot easily in a separate blade template; in fact, as blade is just PHP, I have access to a whole lot of features outside of the scope of backpack itself if needed.

As I planned to use the CRM tab/feature in a lot of models, I just made a custom view model-agnostic that passes the model name and id (as I am in the edit view, I have access to those in $entry). The modal popups to add or program an event (Blue and Orange buttons) ajax-store their values and ajax-refresh a div inside that custom view, so adding CRM functionality to any Model is now a matter of adding a custom field in backpack, the same for all models:

php $this->crud->addField([ 'name' => 'crm_view', 'type' => 'view', 'view' => 'admin/crm/list', 'tab' => 'CRM', 'wrapperAttributes' => ['class' => 'form-group col-md-12'] ], 'update');

You can see the buttons and view in action around half of this short video (along with voice control!)

All 13 comments

Hi @MarcosBL ,

Hmm... I'm wondering - does it really make sense to eager load the relationships when it's just one entry? What kind of performance boost would it offer?

If that's an issue for a particular model, it sounds to me more like a globalScope on the model, that would always eager load that, would be more helpful right?

I don't know :-) I don't know. Could be wrong on this one.

Cheers!

I found a way to eager load them with ->load in the view, so I managed to fix my problem, but commented it as a "consistency" problem. If we define the eager loading relationships in the CRUD we should be able to access them everywhere, nowadays we have that problem also with the AjaxTables, with the search, etc, inconsistency between what is available and what not in the list/edit/pagination/etc areas. Just wanted to reduce one of them.

My use case: I have some entities (Schools, Teachers, Students, etc...) that share a Morhpmany "CRM" model. That model specifies wich Comercial sent What to that Model, for example:

  • Lola (CRM_Comercial model) made a call (CRM_actions model) to company A (Companies model) talking about X on 2017-04-01
  • Silvia (CRM_Comercial model) sent an email (CRM_actions model) to same company A (Companies model) talking about Y on 2017-04-02

That allows me to easily attach a CRM history log to any model on my database (Schools, Teachers, Students, etc...) and provides a great history log of what happens at the company in case someone is ill, on vacation, etc...

image

I also use that info to draw a calendar of daily actions in the company, so anyone can eagle-view all the work done daily

image

The problem is, when I am editing a company with 50 CRM events, as each event have a Comercial and a Action relations, I end up with (50 * 2 model fields) 100 aditional queries to the database, mostly duplicates, as I have only 4 Comercials and 10 different Actions. If I eager load that relations, it becomes just 2 queries, despite having 2 fields or 10, 50 events or 5000.

So in my use case the speed boost is important, but now I must find the entry again and eager load it's relations before the listing:

````php

{{-- We need to eager load, backpack doesn't do it for us --}} @include('admin.crm.crm-history', ['entry' => $crud->model::with(['crm', 'crm.accion', 'crm.comercial'])->find($entry->id) ])

````
Or, a bit easier:

````php

{{-- We need to eager load, backpack doesn't do it for us --}} @include('admin.crm.crm-history', ['entry' => $entry->load(['crm', 'crm.accion', 'crm.comercial'])

````
I can't conclude if it is for the majority of users, but my thoughts are if you don't need it, you'll probably not eager load them in the CRUD, and if you do, you'll probably use them in the edit view as well. Also, +1 for consistency.

@MarcosBL - did you make a custom edit view here?

@lloy0076 Not exactly, I used the standard edit view but added a custom field using a custom view: that way I can extend a lot easily in a separate blade template; in fact, as blade is just PHP, I have access to a whole lot of features outside of the scope of backpack itself if needed.

As I planned to use the CRM tab/feature in a lot of models, I just made a custom view model-agnostic that passes the model name and id (as I am in the edit view, I have access to those in $entry). The modal popups to add or program an event (Blue and Orange buttons) ajax-store their values and ajax-refresh a div inside that custom view, so adding CRM functionality to any Model is now a matter of adding a custom field in backpack, the same for all models:

php $this->crud->addField([ 'name' => 'crm_view', 'type' => 'view', 'view' => 'admin/crm/list', 'tab' => 'CRM', 'wrapperAttributes' => ['class' => 'form-group col-md-12'] ], 'update');

You can see the buttons and view in action around half of this short video (along with voice control!)

Pff... still not sure on this one - if it's overoptimization or not. In your use case it sounds reasonable, but I don't know how many people would actually need this, and how a solution would look.

What do you guys think - should close this or not?

Cheers!

My take:

Even if I found a way to do it, I still see a consistency problem: if we define the eager loading relationships in the CRUD, we should be able to access them in all CRUD operations.

If you only use backpack as a simple CRUD, maybe it will not be needed, but if you are editing a "Client":

  • Client->Orders->Products
  • Client->Shipping->Addresses
  • etc..

Lot of places where a eager loading can be helpful

I'm not convinced the time taken to find a solution might justify the time saved by just coping with a few hundred more requests.

Laravel 4 & 5

// Accepts a single relation (string) or an array of relations for eager loading. $model->load($ModelEagerRelationshipDefinedArray);

I'm gonna have to agree with @lloy0076 on this one. I don't think this is an issue for 99.9% of the CRUDs. That's probably why it's the first time I hear about it :-)

You're building something super-complex there (which looks wonderful, btw, nice job), so _some_ customization is expected in such a case. If I were you, I wouldn't go with eager loading, but with as much AJAX as possible...

Cheers!

It's fair ! Anyone looking for this will find the solution in this thread, so... onto another issue! :+1:

I found a way to eager load them with ->load in the view, so I managed to fix my problem, but commented it as a "consistency" problem. If we define the eager loading relationships in the CRUD we should be able to access them everywhere, nowadays we have that problem also with the AjaxTables, with the search, etc, inconsistency between what is available and what not in the list/edit/pagination/etc areas. Just wanted to reduce one of them.

My use case: I have some entities (Schools, Teachers, Students, etc...) that share a Morhpmany "CRM" model. That model specifies wich Comercial sent What to that Model, for example:

* Lola (CRM_Comercial model) made a call (CRM_actions model) to company A (Companies model) talking about X on 2017-04-01

* Silvia (CRM_Comercial model) sent an email (CRM_actions model) to same company A (Companies model) talking about Y on 2017-04-02

That allows me to easily attach a CRM history log to any model on my database (Schools, Teachers, Students, etc...) and provides a great history log of what happens at the company in case someone is ill, on vacation, etc...

image

I also use that info to draw a calendar of daily actions in the company, so anyone can eagle-view all the work done daily

image

The problem is, when I am editing a company with 50 CRM events, as each event have a Comercial and a Action relations, I end up with (50 * 2 model fields) 100 aditional queries to the database, mostly duplicates, as I have only 4 Comercials and 10 different Actions. If I eager load that relations, it becomes just 2 queries, despite having 2 fields or 10, 50 events or 5000.

So in my use case the speed boost is important, but now I must find the entry again and eager load it's relations before the listing:

<div class="col-md-12">
  {{-- We need to eager load, backpack doesn't do it for us --}}
  @include('admin.crm.crm-history', ['entry' => $crud->model::with(['crm', 'crm.accion', 'crm.comercial'])->find($entry->id) ])
</div>

Or, a bit easier:

<div class="col-md-12">
  {{-- We need to eager load, backpack doesn't do it for us --}}
  @include('admin.crm.crm-history', ['entry' => $entry->load(['crm', 'crm.accion', 'crm.comercial'])
</div>

I can't conclude if it is for the majority of users, but my thoughts are if you don't need it, you'll probably not eager load them in the CRUD, and if you do, you'll probably use them in the edit view as well. Also, +1 for consistency.

how to create like the first image?

@anditsung it's just a single custom 12-cols field in a tab, then in the custom view you can do anything you need to

As well, If you have a custom edit or show view that need eager loading, you can use "load" in your CRUD controller, like this:

```php
public function show($id)
{

    $content = $this->traitShow($id); 
    $this->crud->entry->load([ 
        'relation_1',
        'relation_2',
        'relation_xxx',
    ]);  
    return $content;
 }
Was this page helpful?
0 / 5 - 0 ratings