如何通过预加载获取Scheme关联Sponsor的对应ContributionRate数据
问题
我有Scheme和Sponsor两个模型,二者通过中间表SchemeSponsor建立多对多关联。中间表SchemeSponsor与ContributionRate模型是一对多关联。我希望获取某个Scheme关联的所有Sponsor,以及每个Sponsor对应的仅与当前Scheme关联的ContributionRate数据。
各模型字段如下:
- Scheme:
- id
- name
- Sponsor:
- id
- name
- SchemeSponsor:
- id
- sponsor_id
- scheme_id
- pivot_data
- ContributionRate:
- id
- scheme_sponsor_id
- rate
目前我在Sponsor模型中定义了如下关联:
public function contribution_rates() { return $this->hasManyThrough( ContributionRates::class, SchemeSponsor::class, 'sponsor_id', 'scheme_sponsor_id', 'id', 'id' ); }
但该关联会返回该Sponsor所有的ContributionRate数据,包括和其他Scheme关联的无关数据。我需要通过预加载实现只获取与当前Scheme绑定的中间表对应的ContributionRate数据。
解决方案
1. 调整模型关联,利用中间表模型嵌套关联
hasManyThrough无法直接过滤出绑定特定Scheme的关联数据,我们可以通过多对多关联的中间表模型来嵌套关联ContributionRate:
首先在Scheme模型中正确定义多对多关联,指定中间表模型并带上必要字段:
// Scheme.php public function sponsors() { return $this->belongsToMany(Sponsor::class) ->using(SchemeSponsor::class) // 指定中间表模型 ->withPivot('id', 'pivot_data'); // 带上中间表ID,用于关联ContributionRate }
然后在SchemeSponsor模型中定义与ContributionRate的一对多关联:
// SchemeSponsor.php public function contributionRates() { return $this->hasMany(ContributionRate::class, 'scheme_sponsor_id'); }
2. 嵌套预加载获取目标数据
现在可以通过嵌套预加载,直接从指定Scheme获取关联的Sponsor,以及每个Sponsor对应的绑定当前Scheme的ContributionRate:
$targetSchemeId = 1; // 替换为你的目标Scheme ID $scheme = Scheme::with('sponsors.pivot.contributionRates') ->find($targetSchemeId);
3. 访问数据的方式
获取数据后,可按以下方式访问:
foreach ($scheme->sponsors as $sponsor) { // 当前Scheme与该Sponsor的中间表记录 $schemeSponsor = $sponsor->pivot; // 对应的ContributionRate数据 $rates = $schemeSponsor->contributionRates; }
替代方案:带条件的动态关联
如果希望直接在Sponsor模型中定义过滤特定Scheme的关联,可以使用闭包传入Scheme ID:
// Sponsor.php public function contributionRatesForScheme($schemeId) { return $this->hasManyThrough( ContributionRate::class, SchemeSponsor::class, 'sponsor_id', 'scheme_sponsor_id', 'id', 'id' )->where('scheme_sponsors.scheme_id', $schemeId); }
预加载时通过闭包指定条件:
$targetSchemeId = 1; $scheme = Scheme::with(['sponsors' => function ($query) use ($targetSchemeId) { $query->with(['contributionRatesForScheme' => function ($q) use ($targetSchemeId) { $q->where('scheme_sponsors.scheme_id', $targetSchemeId); }]); }])->find($targetSchemeId);
不过这种方式不如第一种嵌套预加载直观,推荐优先使用第一种方案。
内容的提问来源于stack exchange,提问作者Tim Kariuki
相关产品推荐
相关产品推荐

