Won*_*nka 28 polymorphism polymorphic-associations eager-loading laravel eloquent
我可以在没有任何n + 1问题的情况下急切加载多态关系/模型.但是,如果我尝试访问与多态模型相关的模型,则会出现n + 1问题,而我似乎无法找到修复.以下是在本地查看的确切设置:
1)DB表名/数据
history

companies

products

services

2)模型
// History
class History extends Eloquent {
protected $table = 'history';
public function historable(){
return $this->morphTo();
}
}
// Company
class Company extends Eloquent {
protected $table = 'companies';
// each company has many products
public function products() {
return $this->hasMany('Product');
}
// each company has many services
public function services() {
return $this->hasMany('Service');
}
}
// Product
class Product extends Eloquent {
// each product belongs to a company
public function company() {
return $this->belongsTo('Company');
}
public function history() {
return $this->morphMany('History', 'historable');
}
}
// Service
class Service extends Eloquent {
// each service belongs to a company
public function company() {
return $this->belongsTo('Company');
}
public function history() {
return $this->morphMany('History', 'historable');
}
}
Run Code Online (Sandbox Code Playgroud)
3)路由
Route::get('/history', function(){
$histories = History::with('historable')->get();
return View::make('historyTemplate', compact('histories'));
});
Run Code Online (Sandbox Code Playgroud)
4)只有$ history-> historable-> company-> name记录n + 1的模板,将其注释掉,n + 1消失..但我们需要那个遥远的相关公司名称:
@foreach($histories as $history)
<p>
<u>{{ $history->historable->company->name }}</u>
{{ $history->historable->name }}: {{ $history->historable->status }}
</p>
@endforeach
{{ dd(DB::getQueryLog()); }}
Run Code Online (Sandbox Code Playgroud)
我需要能够急切地加载公司名称(在单个查询),因为它是多态的关系模型的相关模型Product和Service.我已经工作了好几天但找不到解决方案.
History::with('historable.company')->get()只是忽略了companyin historable.company.这个问题的有效解决方案是什么?
dam*_*ani 58
解:
如果你添加:
protected $with = ['company'];
Run Code Online (Sandbox Code Playgroud)
同时Service和Product模特.这样,company每次加载Service或加载时都会急切地加载关系Product,包括通过多态关系加载时History.
说明:
这将导致额外的2个查询,一个用于Service一个查询,一个用于Product查询,即每个查询一个查询historable_type.所以你的查询总数 - 不管结果的数量 - n来自m+1(没有急切加载远距离company关系)(m*2)+1,其中m是你的多态关系链接的模型数量.
可选的:
这种方法的缺点是你总是急于加载和模型company上的关系.这可能是也可能不是问题,具体取决于数据的性质.如果这是一个问题,您可以使用此技巧仅在调用多态关系时自动加载.ServiceProductcompany
将此添加到您的History模型:
public function getHistorableTypeAttribute($value)
{
if (is_null($value)) return ($value);
return ($value.'WithCompany');
}
Run Code Online (Sandbox Code Playgroud)
现在,当你加载historable多态关系,雄辩会寻找类ServiceWithCompany和ProductWithCompany,而不是Service或Product.然后,创建这些类,并with在其中设置:
ProductWithCompany.php
class ProductWithCompany extends Product {
protected $table = 'products';
protected $with = ['company'];
}
Run Code Online (Sandbox Code Playgroud)
ServiceWithCompany.php
class ServiceWithCompany extends Service {
protected $table = 'services';
protected $with = ['company'];
}
Run Code Online (Sandbox Code Playgroud)
...最后,您可以protected $with = ['company'];从基础Service和Product类中删除.
有点hacky,但它应该工作.
Raz*_*zor 10
你可以分开集合,然后懒得加载每一个:
$histories = History::with('historable')->get();
$productCollection = new Illuminate\Database\Eloquent\Collection();
$serviceCollection = new Illuminate\Database\Eloquent\Collection();
foreach($histories as $history){
if($history->historable instanceof Product)
$productCollection->add($history->historable);
if($history->historable instanceof Service)
$serviceCollection->add($history->historable);
}
$productCollection->load('company');
$serviceCollection->load('company');
// then merge the two collection if you like
foreach ($serviceCollection as $service) {
$productCollection->push($service);
}
$results = $productCollection;
Run Code Online (Sandbox Code Playgroud)
可能它不是最好的解决方案,protected $with = ['company'];按照@damiani的建议添加是一个很好的解决方案,但这取决于您的业务逻辑.
只需更新您的 Laravel 版本和以下代码
protected $with = [‘likeable.owner’];
Run Code Online (Sandbox Code Playgroud)
将按预期工作。
| 归档时间: |
|
| 查看次数: |
15691 次 |
| 最近记录: |