为什么 laravel 模型复制数据集以及如何(如果可能)只有一组数据


Why laravel model duplicates set of data and how (if possible) to have only one set of data?

Laravel模型提供了一种可以从另一个关联表返回结果的方法很方便。

例如,我有一个名为item的表和另一个称为反馈的表,其中反馈表在项目表中存储项目的反馈。因此,要获得 id 为 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
               )
       )
)

它工作正常,并且显示对 ID 为 1 的项目只有一个反馈。

我担心的是数据集在[attributes:protected][original:protected]中重复。这只是一个测试用例,真实案例将包含数千个反馈,拥有重复的数据集会浪费大量内存。如果我使用 DB::table('table_name') 方法,则数据集不会重复,但这不太方便。

为什么 laravel 需要复制模型中的数据?

有没有办法让它只返回一组数据?

目前,我正在使用->toArray()在查询后立即修剪不必要的数据,但是内存使用情况仍然存在,因为laravel仍在创建该组数据。

虽然很难得到一个好的例子,但它允许您在绝对保存属性之前设置属性。如果您遍历许多函数并最终检查是否已正确设置所有内容以进行最终保存,而无需将所有内容存储在单独的变量中,可能会很好。

非常小的例子:

$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'
   ...
)

只有在 save() 之后,数据才真正保存到数据库中。

Eloquent 的 syncOriginal() 在模型被保存()'d 时被触发:

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

存储原始数据是为了允许模型执行脏检查。脏检查在内部用于处理数据库更新。

如果模型不脏,并且您尝试保存它,则不会执行任何更新。如果模型是脏的,并且您尝试保存它,则只会更新那些脏的字段。

如果你真的想摆脱它,你可以覆盖模型上的syncOriginal()syncOriginalAttribute()方法。但是,如果您这样做,则意味着该模型将始终被视为脏污。 getDirty()将始终返回所有属性,isDirty()将始终返回true

如果使用时间戳,则还需要覆盖 updateTimestamps() 方法,否则将永远不会设置updated_atcreated_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的操作吗?队列中的单个作业是否可以更好地完成这项工作?等。。。

考虑到 PHP 在内部的工作方式,这应该不是问题。除非"属性"不被修改,否则"属性"只是指向"原始"(或相反)的指针,因此两个数组占用的内存量几乎与只有一个数组的内存量相同。这就是为什么当您执行toArray()时内存使用情况不会改变的原因。

详情请参阅此链接:http://blog.ircmaxell.com/2014/12/what-about-garbage.html