Laravel三元关系模型关联通用实现方案咨询
Laravel三元多对多关系的通用实现方案
现有数据表结构
Questionnaire表
Schema::create('questionnaires', function (Blueprint $table) { $table->id('id'); $table->string('Quanti'); $table->date('date_heure'); $table->timestamps(); });
Responses表
Schema::create('reponses', function (Blueprint $table) { $table->id('id'); $table->string('libelle_reponse', 50); $table->integer('ordre'); $table->timestamps(); });
Questions表
Schema::create('questions', function (Blueprint $table) { $table->id('id'); $table->string('libelle_question', 50); $table->integer('ordre'); $table->string('graphique', 50); $table->foreignId('type_id')->constrained('type', 'id'); $table->timestamps(); });
三元中间表 questionnaire_reponse_question
Schema::create('questionnaire_reponse_question', function (Blueprint $table) { $table->foreignId('reponse_id')->constrained('reponses', 'id'); $table->foreignId('question_id')->constrained('questions', 'id'); $table->foreignId('questionnaire_id')->constrained('questionnaires', 'id'); $table->primary(['reponse_id', 'questionnaire_id', 'question_id']); $table->timestamps(); });
通用实现方案
除了自定义Pivot模型,有两种更通用的实现思路:
方案1:规范使用带额外字段的belongsToMany关联
Laravel原生的belongsToMany支持通过withPivot获取中间表字段,可通过在模型中定义双向关联适配三元场景:
模型关联定义
- Questionnaire模型:
class Questionnaire extends Model { public function questions() { return $this->belongsToMany(Question::class, 'questionnaire_reponse_question') ->withPivot('reponse_id', 'created_at', 'updated_at') ->withTimestamps(); } public function responses() { return $this->belongsToMany(Response::class, 'questionnaire_reponse_question') ->withPivot('question_id', 'created_at', 'updated_at') ->withTimestamps(); } }
- Question模型:
class Question extends Model { public function questionnaires() { return $this->belongsToMany(Questionnaire::class, 'questionnaire_reponse_question') ->withPivot('reponse_id', 'created_at', 'updated_at') ->withTimestamps(); } public function responses() { return $this->belongsToMany(Response::class, 'questionnaire_reponse_question') ->withPivot('questionnaire_id', 'created_at', 'updated_at') ->withTimestamps(); } }
- Response模型:
class Response extends Model { public function questionnaires() { return $this->belongsToMany(Questionnaire::class, 'questionnaire_reponse_question') ->withPivot('question_id', 'created_at', 'updated_at') ->withTimestamps(); } public function questions() { return $this->belongsToMany(Question::class, 'questionnaire_reponse_question') ->withPivot('questionnaire_id', 'created_at', 'updated_at') ->withTimestamps(); } }
查询示例
获取某个问卷下的所有问题及对应的回答:
$questionnaire = Questionnaire::find(1); foreach ($questionnaire->questions as $question) { $response = Response::find($question->pivot->reponse_id); // 处理业务逻辑 }
方案2:将中间表作为独立Eloquent模型(推荐)
把三元中间表视为独立业务模型(比如命名为QuestionnaireResponseQuestion),通过一对多关联连接三个主模型,这种方式更灵活,适配复杂业务逻辑:
1. 创建中间模型
namespace App\Models; use Illuminate\Database\Eloquent\Model; class QuestionnaireResponseQuestion extends Model { protected $table = 'questionnaire_reponse_question'; protected $primaryKey = ['reponse_id', 'questionnaire_id', 'question_id']; public $incrementing = false; // 定义关联 public function questionnaire() { return $this->belongsTo(Questionnaire::class); } public function question() { return $this->belongsTo(Question::class); } public function response() { return $this->belongsTo(Response::class); } }
2. 主模型添加关联
- Questionnaire模型:
public function questionnaireResponseQuestions() { return $this->hasMany(QuestionnaireResponseQuestion::class); }
- Question模型:
public function questionnaireResponseQuestions() { return $this->hasMany(QuestionnaireResponseQuestion::class); }
- Response模型:
public function questionnaireResponseQuestions() { return $this->hasMany(QuestionnaireResponseQuestion::class); }
查询示例
获取某个问卷的所有提交记录(包含问题和回答):
$submissions = QuestionnaireResponseQuestion::where('questionnaire_id', 1) ->with(['question', 'response']) ->get(); foreach ($submissions as $submission) { echo $submission->question->libelle_question; echo $submission->response->libelle_reponse; }
新增记录示例
QuestionnaireResponseQuestion::create([ 'questionnaire_id' => 1, 'question_id' => 2, 'reponse_id' => 3, ]);
这种方案优势在于:可直接对中间表进行CRUD操作,轻松添加验证、钩子等业务逻辑,支持复杂查询条件,完全契合Laravel Eloquent设计思想。
内容的提问来源于stack exchange,提问作者Swen NEVEU
相关产品推荐
相关产品推荐

