You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Laravel关联关系场景下如何正确使用firstOrCreate方法?

在Laravel Eloquent中结合关联模型使用firstOrCreate的正确姿势

没问题,这种场景完全可以用firstOrCreate!我来帮你分析下问题出在哪,以及怎么解决:

先修正模型里的小问题

你的Athlete模型中,$fillable数组包含了'nation',但这个是关联关系的名称,不是数据库实际存储的字段——数据库里对应的外键应该是nation_id(这是Eloquent belongsTo关联的默认命名规则)。所以首先要调整Athlete$fillable

class Athlete extends Model {
    public $timestamps = false;
    // 把nation_id加入可填充字段,移除不需要的'nation'(如果数据库没有这个字段的话)
    protected $fillable = ['firstname', 'lastname', 'nation_id', 'sex'];  

    public function nation() {
        return $this->belongsTo('App\Nation');
    }
}

两种正确的实现方式

方式一:直接通过Athlete模型调用

修正$fillable之后,你第一种写法的思路是对的,现在可以正常运行了:

$ath = Athlete::firstOrCreate([
    'nation_id' => $nation->id,
    'lastname' => $nn,
    'sex' => $sex,
    'firstname' => $vn
]);

之前报错的原因

之前的错误"Nation_id doesn't have a default value",是因为nation_id不在$fillable数组中,当创建新记录时,Laravel不会将这个字段赋值到模型里,导致数据库插入时缺少必填的外键字段。


方式二:通过关联关系调用(更推荐)

利用Eloquent的关联关系来操作会更优雅,Laravel会自动帮你处理nation_id的赋值,不需要手动传入:

$ath = $nation->athletes()->firstOrCreate([
    'lastname' => $nn,
    'sex' => $sex,
    'firstname' => $vn
]);

这种方式的好处是,你不需要在查询条件里手动写nation_id,关联关系会自动把当前$nation的ID绑定到新创建的Athlete记录上,同时也规避了$fillable的限制(因为关联创建外键时会绕过fillable检查)。

为什么你的第二种写法不行?

你尝试直接传入['nation' => $nation]作为查询条件,这是错误的——firstOrCreate的参数需要的是数据库字段的键值对,而不是关联模型对象。Laravel会尝试把这个对象转换成字符串来构建WHERE语句,这显然不符合数据库查询的要求,所以会失败。

内容的提问来源于stack exchange,提问作者gnarf

火山引擎 最新活动