【问题标题】:Saving multiple IDs in a HasMany Eloquent relationship在 HasMany Eloquent 关系中保存多个 ID
【发布时间】:2018-12-25 07:25:21
【问题描述】:

我有一个模型Foo,它有很多Bars:

class Foo extends Model
{
    public function bars()
    {
        return $this->hasMany('App\Bar');
    }
}

class Bar extends Model
{
    public function foo()
    {
        return $this->belongsTo('App\Foo');
    }
}

当保存一个新的Foo 时,请求负载带有一个Bar ids 数组。我想同时保存这些。这有效:

public function store(StoreFoo $request)
{
    $foo = Foo::create($request->validated());
    foreach ($request->barIds as $barId) {
        $foo->bars()->create(['bar_id' => $barId]);
    }
}

我的问题是:有没有办法在没有循环的情况下做到这一点?我尝试过syncattach,但这些不适用于这种情况。

【问题讨论】:

  • createMany() 但这并不能真正简化您的代码。

标签: php laravel eloquent relationship


【解决方案1】:

迁移表示例

Schema::create('logs', function(Blueprint $table) {
    $table->bigIncrements('id');
    $table->unsignedBigInteger('user_id')->default(0)->index();
    $table->string('type', 10)->index(); // add, update, delete
    $table->string('table', 50)->index();
    $table->unsignedBigInteger('row');
    $table->dateTime('created_at');
});
Schema::create('log_fields', function(Blueprint $table) {
    $table->bigIncrements('id');
    $table->unsignedBigInteger('log_id')->index();
    $table->string('field', 50)->index();
    $table->longText('old');
    $table->longText('new');
});

模型Log.php文件

class Log extends Model
{
    const UPDATED_AT = null;
    protected $fillable = [
        'user_id',
        'type',
        'table',
        'row'
    ];

    public function logFields()
    {
        return $this->hasMany(LogField::class);
    }
}

模型 LogField.php 文件

class LogField extends Model
{
    public    $timestamps = false;
    protected $fillable   = [
        'field',
        'old',
        'new'
    ];

    public function log()
    {
        return $this->belongsTo(Log::class);
    }
}

另一个模型的启动功能,用于保存数据库中的更改。 钩子创建,更新和删除以回答您的问题

public static function boot()
    {
        parent::boot();

        static::created(function($resorce) {
            $_log = new Log;
            $_log->create([
                'user_id' => session('uid', 0),
                'type'    => 'add',
                'table'   => $resorce->getTable(),
                'row'     => $resorce->fresh()->toArray()['id']
            ]);

            return true;
        });

        static::updating(function($resorce) {
            $_log = new Log;
            $log = $_log->create([
                'user_id' => session('uid', 0),
                'type'    => 'update',
                'table'   => $resorce->getTable(),
                'row'     => $resorce->fresh()->toArray()['id']
            ]);

            foreach($resorce->getDirty() as $field => $new) {
                $log->logFields()->create([
                    'field'  => $field,
                    'old'    => $resorce->fresh()->toArray()[$field],
                    'new'    => $new
                ]);
            }

            return true;
        });

        static::deleting(function($resorce) {
            $_log = new Log;
            $log = $_log->create([
                'user_id' => session('uid', 0),
                'type'    => 'delete',
                'table'   => $resorce->getTable(),
                'row'     => $resorce->id,
            ]);

            foreach($resorce->fresh()->toArray() as $field => $value) {
                $log->logFields()->create([
                    'field'  => $field,
                    'old'    => '',
                    'new'    => $value
                ]);
            }

            return true;
        });
    }

希望我能帮助你理解这一点。

【讨论】:

    【解决方案2】:

    我能想到的唯一方法是在HasMany 关系上使用saveMany 方法,无需自己编写循环即可实现此目的。您可以创建 Bar 模型的实例并将它们作为数组全部传递给 saveMany 方法,这将保存所有实例并返回创建的实体数组作为响应。

    $foo->bars()->saveMany([new Bar(['id' => 1]), new Bar(['id' => 2])]);
    

    话虽如此,Laravel 使用循环在后台一个一个地保存这些模型,因此它与您现在所做的并没有太大的不同。

    同样,还有一个 createMany 方法,您可以像使用 saveMany 一样使用它,但您可以提供属性数组,而不是提供新创建的模型。

    【讨论】:

    • 但是如果我事先不知道$request->barIds 数组会有多大,我想我不能用这个,对吧?
    • 我想这完全取决于您的输入可能是什么。如果您有一对多关系(看起来确实如此),那么也许您可以使用Model::insert() 方法批量创建 many 模型。如果来自您的请求的 barIds 是一个数组,您可以将其转换为一个集合并将其分块,这样您一次只插入 X 条记录。
    猜你喜欢
    • 2020-05-31
    • 2021-11-01
    • 2019-08-12
    • 2016-03-17
    • 1970-01-01
    • 2020-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多