Laravel多对多关联下用户活动完成记录的模型关系定义咨询
嘿,这个场景我之前做项目的时候也碰到过,咱们先把第一种方案的模型关联理清楚,顺便也聊聊两种方案的取舍~
方案1的模型关联实现详解
首先明确表结构逻辑:assignments是用户和活动的「分配关系」(比如给用户A分配了活动X),而completions是用户「每次完成该分配活动」的记录——关联assignments的设计能把“完成”和“分配”的上下文绑定起来,逻辑更严谨。
接下来逐个模型的关联代码实现:
1. User 模型
用户可以拥有多个分配记录,也能通过分配记录关联到所有完成记录:
class User extends Model { // 用户 ← 多个分配记录 public function assignments() { return $this->hasMany(Assignment::class); } // 用户 ← 通过分配记录 ← 多个完成记录 public function completions() { return $this->hasManyThrough(Completion::class, Assignment::class); } // 用户 ↔ 活动的多对多关联(原核心关联) public function activities() { return $this->belongsToMany(Activity::class, 'assignments'); } }
2. Activity 模型
和User模型逻辑类似,活动可以被分配给多个用户,也能通过分配记录关联到所有完成记录:
class Activity extends Model { // 活动 ← 多个分配记录 public function assignments() { return $this->hasMany(Assignment::class); } // 活动 ← 通过分配记录 ← 多个完成记录 public function completions() { return $this->hasManyThrough(Completion::class, Assignment::class); } // 活动 ↔ 用户的多对多关联(原核心关联) public function users() { return $this->belongsToMany(User::class, 'assignments'); } }
3. Assignment 模型
这是连接用户、活动和完成记录的核心中间模型:
class Assignment extends Model { // 分配记录 → 属于某个用户 public function user() { return $this->belongsTo(User::class); } // 分配记录 → 属于某个活动 public function activity() { return $this->belongsTo(Activity::class); } // 分配记录 ← 多个完成记录(用户多次完成该分配的活动) public function completions() { return $this->hasMany(Completion::class); } }
4. Completion 模型
完成记录直接关联到分配记录,同时可以快捷关联到用户和活动:
class Completion extends Model { // 完成记录 → 属于某个分配记录 public function assignment() { return $this->belongsTo(Assignment::class); } // 【可选】直接获取完成记录对应的用户(需安装 `staudenmeir/belongs-to-through` 扩展包) public function user() { return $this->belongsToThrough(User::class, Assignment::class); } // 【可选】直接获取完成记录对应的活动(同上,需扩展包) public function activity() { return $this->belongsToThrough(Activity::class, Assignment::class); } }
如果不想用第三方扩展包,也可以直接通过$completion->assignment->user或$completion->assignment->activity获取关联的用户/活动,只是多了一层调用而已。
常用操作示例
- 获取某个用户的所有完成记录:
$user->completions - 获取某个分配记录下的所有完成记录:
$assignment->completions - 给某个分配记录新增一条完成记录:
$assignment = Assignment::find(1); $assignment->completions()->create([ 'completed_at' => now(), // 可添加其他字段比如备注、耗时等 ]);
两种方案的简单对比
最后说下两种方案的取舍,方便你做决策:
- 方案1(关联assignment_id):优点是无数据冗余,能保留「用户被分配该活动」的上下文(比如
assignment里如果有截止时间、分配人等字段,completion可以直接关联获取);缺点是查询完成记录的用户/活动时多了一层关联,略复杂。 - 方案2(直接存user_id+activity_id):优点是查询用户和活动的完成记录更直接,不需要经过
assignment;缺点是冗余存储了user_id和activity_id,如果后续assignment的信息有变更,completion无法关联到历史分配上下文。
内容的提问来源于stack exchange,提问作者blackbird
相关产品推荐
相关产品推荐

