Подтвердить что ты не робот

Почему модель laravel дублирует набор данных и как (если возможно) иметь только один набор данных?

Удобно, что модель laravel предоставляет метод, позволяющий возвращать результаты из другой связанной таблицы.

Например, у меня есть таблица, называемая элементом, а другая таблица называется обратной связью, где в таблице обратной связи хранится обратная связь элемента в таблице элементов. Итак, чтобы получить всю обратную связь элемента с идентификатором 1, я сделаю следующее:

Item::find(1)->feedback;

И после этого распечатается возвращаемый объект.

Illuminate\Database\Eloquent\Collection Object
(    [items:protected] => Array
       (
           [0] => Feedback Object
               (
                   [table:protected] => feedback
                   [connection:protected] => 
                   [primaryKey:protected] => id
                   [perPage:protected] => 15
                   [incrementing] => 1
                   [timestamps] => 1
                   [attributes:protected] => Array
                       (
                           [id] => 1
                           [rma_id] => 3
                           [item_id] => 8
                           [quo_id] => 0
                           [case_id] => i2eM20160120
                           [line_no] => 000001
                           [content] => test
                           [status] => sent
                           [read] => 0
                           [sender] => Tester
                           [created_at] => 2016-01-20 18:03:44
                           [updated_at] => 2016-01-20 18:03:44
                       )

                   [original:protected] => Array
                       (
                           [id] => 1
                           [rma_id] => 3
                           [item_id] => 8
                           [quo_id] => 0
                           [case_id] => i2eM20160120
                           [line_no] => 000001
                           [content] => test
                           [status] => sent
                           [read] => 0
                           [sender] => Tester
                           [created_at] => 2016-01-20 18:03:44
                           [updated_at] => 2016-01-20 18:03:44
                       )

                   [relations:protected] => Array
                       (
                       )

                   [hidden:protected] => Array
                       (
                       )

                   [visible:protected] => Array
                       (
                       )

                   [appends:protected] => Array
                       (
                       )

                   [fillable:protected] => Array
                       (
                       )

                   [guarded:protected] => Array
                       (
                           [0] => *
                       )

                   [dates:protected] => Array
                       (
                       )

                   [touches:protected] => Array
                       (
                       )

                   [observables:protected] => Array
                       (
                       )

                   [with:protected] => Array
                       (
                       )

                   [morphClass:protected] => 
                   [exists] => 1
               )

       )

)

Он отлично работает, и он показывает, что есть только одна обратная связь по элементу с идентификатором 1.

Меня интересует, что набор данных дублируется в [attributes:protected] и [original:protected]. Это всего лишь случай тестирования, и реальный случай будет состоять из тысяч отзывов и дублирования данных - огромная трата памяти. Набор данных не дублируется, если я использую подход DB::table('table_name'), но это гораздо менее удобно.

Почему laravel нужно дублировать данные в модели?

И есть ли способ вернуть только один набор данных?

В настоящее время я использую ->toArray(), чтобы обрезать ненужные данные сразу после запроса, но использование памяти все еще существует, потому что laravel все еще создает этот набор данных.

4b9b3361

Ответ 1

Пока сложно найти хороший пример, он позволяет вам устанавливать атрибуты, прежде чем их сохранить. Наверное, хорошо, если вы пройдете множество функций и, наконец, проверьте, правильно ли установлено все для окончательного сохранения без необходимости хранить все в разных переменных.

Очень маленький пример:

$user = User::find(1);
print_r($user);
$user->name = 'John Doe';
print_r($user);
$user->save();
print_r($user());

Возвращает что-то вроде:

Первая печать:

[attributes:protected] => Array
(
   [id] => 1
   [name] => 'Jimmy Doe'
   ...
)
[original:protected] => Array
(
   [id] => 1
   [name] => 'Jimmy Doe'
   ...
)

Вторая печать:

[attributes:protected] => Array
(
   [id] => 1
   [name] => 'John Doe'
   ...
)
[original:protected] => Array
(
   [id] => 1
   [name] => 'Jimmy Doe'
   ...
)

Печатная версия:

[attributes:protected] => Array
(
   [id] => 1
   [name] => 'John Doe'
   ...
)
[original:protected] => Array
(
   [id] => 1
   [name] => 'John Doe'
   ...
)

Только после сохранения() данные фактически сохраняются в БД.

Экзотический синкоригинал() запускается, когда модель сохраняет() 'd:

/**
 * Sync the original attributes with the current.
 *
 * @return $this
 */
public function syncOriginal()
{
    $this->original = $this->attributes;

    return $this;
}

Ответ 2

Исходные данные сохраняются для того, чтобы позволить модели выполнять грязную проверку. Грязная проверка используется внутри для обработки обновлений базы данных.

Если модель не загрязнена и вы пытаетесь ее сохранить, обновление не будет выполнено. Если модель загрязнена и вы пытаетесь ее сохранить, будут обновлены только те поля, которые являются грязными.

Если вы действительно хотите избавиться от этого, вы можете переопределить методы syncOriginal() и syncOriginalAttribute() модели. Если бы вы это сделали, это означало бы, что модель всегда будет считаться грязной. getDirty() всегда будет возвращать все атрибуты, а isDirty() всегда будет возвращать true.

Если вы используете временные метки, вам также необходимо переопределить метод updateTimestamps(), иначе ваши поля updated_at и created_at никогда не будут установлены.

class Feedback extends Model
{
    // ...

    public function syncOriginal()
    {
        return $this;
    }

    public function syncOriginalAttribute($attribute)
    {
        return $this;
    }

    protected function updateTimestamps()
    {
        $time = $this->freshTimestamp();

        $this->setUpdatedAt($time);

        if (! $this->exists) {
            $this->setCreatedAt($time);
        }
    }

    // ...
}

Могут быть другие последствия, которые не проявляются сразу при просмотре кода.

Сказав все это, если у вас возникнет такая озабоченность по поводу памяти, вам, возможно, придется подумать о своем подходе и о том, что вы пытаетесь сделать. Вам действительно нужно загрузить 1000 отзывов сразу? Это операция, которая может быть chunk ed? Эта работа будет лучше обслуживаться отдельными заданиями в очереди? и т.д...

Ответ 3

Это должно быть не проблема, учитывая, как PHP работает внутри. Если "атрибуты" не изменены, "атрибуты" - это просто указатель на "оригинал" (или наоборот), поэтому наличие обоих массивов занимает примерно столько же памяти, сколько имеет только один из них. Вот почему использование памяти не меняется, когда вы выполняете toArray().

Подробнее см. эту ссылку: http://blog.ircmaxell.com/2014/12/what-about-garbage.html