Laravel 5.2中如何设置数组类型外键并建立模型关联?
Laravel中外键数组存储下的关联查询解决方案
嘿,我来帮你搞定这个问题!首先得明确:你遇到空值的核心原因是Laravel的常规一对一/一对多关联是基于单个外键的等值匹配,但你把category_id存成了数组(比如[5,6]这种格式),Eloquent根本没法用常规关联逻辑去匹配数组和单个ID,自然返回空。
下面分两种方案给你,优先推荐符合数据库范式的正确做法,也给你不想改结构的临时方案:
一、推荐方案:改用多对多关联(符合数据库设计范式)
从你的需求来看,一个Type可以属于多个Category,一个Category也能对应多个Type,这是典型的多对多关系,存数组完全是反范式的做法,不仅查询麻烦,还没法用索引、维护成本高。正确的做法是建中间表:
1. 创建中间表迁移
执行迁移创建category_type中间表,用来关联两类数据:
Schema::create('category_type', function (Blueprint $table) { $table->foreignId('category_id')->constrained()->onDelete('cascade'); $table->foreignId('type_id')->constrained()->onDelete('cascade'); $table->primary(['category_id', 'type_id']); // 联合主键避免重复关联 });
2. 定义模型关联
在Category和Type模型里定义多对多关联:
- Category模型:
class Category extends Model { // 一个分类对应多个类型 public function types() { return $this->belongsToMany(Type::class); } }
- Type模型:
class Type extends Model { // 一个类型属于多个分类 public function categories() { return $this->belongsToMany(Category::class); } }
3. 执行目标查询
现在要获取category_id为5、6且名称为test的Type数据,直接用whereHas关联查询即可:
$targetTypes = Type::where('name', 'test') ->whereHas('categories', function ($query) { $query->whereIn('category_id', [5, 6]); }) ->get();
二、临时方案:不修改结构,直接查询数组字段
如果你暂时没法改数据库结构,只能针对数组字段做特殊查询,这里分两种存储格式处理:
情况1:category_id是JSON类型(比如存[5,6])
用MySQL的JSON_CONTAINS函数判断数组是否包含目标ID:
$targetTypes = Type::where('name', 'test') ->where(function ($query) { // 匹配包含5或6的数组 $query->whereRaw('JSON_CONTAINS(category_id, ?)', ['5']) ->orWhereRaw('JSON_CONTAINS(category_id, ?)', ['6']); }) ->get();
情况2:category_id是字符串逗号分隔(比如存"5,6")
用MySQL的FIND_IN_SET函数匹配:
$targetTypes = Type::where('name', 'test') ->where(function ($query) { $query->whereRaw('FIND_IN_SET(?, category_id)', [5]) ->orWhereRaw('FIND_IN_SET(?, category_id)', [6]); }) ->get();
逻辑思路总结
- 问题根源:常规关联依赖单个外键的等值匹配,数组字段无法满足这个逻辑,所以返回空;
- 最优解:多对多关系用中间表是数据库设计的标准做法,既能保证数据完整性,又能高效查询;
- 临时解:通过数据库的数组/字符串匹配函数,绕过Eloquent的常规关联逻辑,直接构造查询条件。
内容的提问来源于stack exchange,提问作者Pawan Dongol
相关产品推荐
相关产品推荐

