在 HasMany Eloquent 关系中保存多个 ID

Posted

技术标签:

【中文标题】在 HasMany Eloquent 关系中保存多个 ID【英文标题】:Saving multiple IDs in a HasMany Eloquent relationship 【发布时间】: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() 但这并不能真正简化您的代码。 【参考方案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 条记录。

以上是关于在 HasMany Eloquent 关系中保存多个 ID的主要内容,如果未能解决你的问题,请参考以下文章

使用 Eloquent Laravel 获取 hasMany 关系

Eloquent 一对多关系的错误

Laravel Eloquent 中的多级深度 hasMany 关系

Eloquent hasMany 没有 id 的关系

Eloquent 自定义关系 hasMany(外域包含由外键连接的文本)

Laravel eloquent apply whereHas on the latest record of hasMany 关系