在 HasMany Eloquent 关系中保存多个 ID
Posted
技术标签:
【中文标题】在 HasMany Eloquent 关系中保存多个 ID【英文标题】:Saving multiple IDs in a HasMany Eloquent relationship 【发布时间】:2018-12-25 07:25:21 【问题描述】:我有一个模型Foo
,它有很多Bar
s:
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]);
我的问题是:有没有办法在没有循环的情况下做到这一点?我尝试过sync
和attach
,但这些不适用于这种情况。
【问题讨论】:
有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 关系
Laravel Eloquent 中的多级深度 hasMany 关系
Eloquent 自定义关系 hasMany(外域包含由外键连接的文本)
Laravel eloquent apply whereHas on the latest record of hasMany 关系