You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 11:12:09