Laravel 5.4 Eloquent关联series与posts表字段覆盖问题求助
解决Laravel Eloquent Join后同名字段被覆盖的问题
嘿,这个问题我之前也碰到过!当你用join查询两个有同名字段的表时,MySQL返回的结果集里后出现的字段会覆盖前面的,所以你的posts.id被series.id给替换掉了,这就是为什么返回的集合里posts的字段值不对。
给你两种靠谱的解决方案:
方案一:显式指定查询字段并给冲突字段加别名
既然是字段重名导致的覆盖,那我们就明确告诉Eloquent要选哪些字段,把冲突的字段用别名区分开。修改你的作用域代码,在join之前加上select方法:
public function scopePublishedRestriction($query) { $date = Carbon::today(); $today = date('Y-m-d', $date->getTimestamp()); // 显式选择posts表的所有字段,给series的冲突字段加别名 $query->select( $this->table . '.*', 'learning_series.id as series_id', 'learning_series.published as series_published', 'learning_series.published_from as series_published_from', 'learning_series.published_to as series_published_to' ) ->accessible() ->join('learning_series', function ($join) use ($today) { // 这里的join逻辑保持不变 $join->on($this->table . '.learning_serie_id', 'learning_series.id') ->where('learning_series.published', 1) ->whereDate('learning_series.published_from', '<=', $today) ->where(function ($join) use ($today) { $join->orWhere(function ($join) use ($today) { $join->whereDate('learning_series.published_to', '>=', $today); }) ->orWhere('learning_series.published_to', '0000-00-00 00:00:00'); }); }) ->where($this->table . '.published', 1) ->where($this->table . '.published_from', '<=', $today) ->where(function ($query) use ($today) { $query->orWhere(function ($query) use ($today) { $query->whereDate($this->table . '.published_to', '>=', $today); }) ->orWhere($this->table . '.published_to', '0000-00-00 00:00:00'); }); return $query; }
这样查询结果里,series的id会变成series_id,不会和posts的id冲突,你可以正常访问所有字段了。
方案二:用Eloquent关联代替手动Join(更推荐)
Laravel的ORM本来就设计了关联关系,用这个方法不仅能避免字段冲突,代码也更优雅易维护。
第一步:定义模型关联
在你的Post模型里定义和Series的关联:
// app/Models/Post.php public function series() { return $this->belongsTo(Series::class, 'learning_serie_id'); }
第二步:给两个模型分别添加发布状态的作用域
先给Series模型加作用域:
// app/Models/Series.php public function scopePublished($query) { $today = Carbon::today()->toDateString(); return $query->where('published', 1) ->whereDate('published_from', '<=', $today) ->where(function ($q) use ($today) { $q->whereDate('published_to', '>=', $today) ->orWhere('published_to', '0000-00-00 00:00:00'); }); }
然后给Post模型加作用域,用whereHas来关联series的发布条件:
// app/Models/Post.php public function scopePublishedRestriction($query) { $today = Carbon::today()->toDateString(); return $query->accessible() ->where('published', 1) ->whereDate('published_from', '<=', $today) ->where(function ($q) use ($today) { $q->whereDate('published_to', '>=', $today) ->orWhere('published_to', '0000-00-00 00:00:00'); }) // 只加载符合发布条件的series对应的posts ->whereHas('series', function ($q) { $q->published(); }); }
使用方式
现在你直接调用Post::publishedRestriction()->get(),返回的每个Post实例里,你可以通过$post->series访问对应的系列模型,完全不会有字段冲突的问题,而且代码结构更清晰,后续修改发布规则也更容易。
两种方案里我更推荐第二种,因为它更符合Laravel的设计思想,也减少了手动写Join的维护成本。
内容的提问来源于stack exchange,提问作者Markus Lenz
相关产品推荐
相关产品推荐

