Eloquent (Laravel 5) - 如何在关系查询 (whereHas) 中包含 SoftDeleted 记录?
Eloquent (Laravel 5) - How do I include SoftDeleted records in relationship queries (whereHas)?
我已经使用 Eloquent 构建了一个存储库层。我在表之间有很多复杂的关系,并且能够使用 eloquent 轻松构建所有查询,我非常依赖 WhereHas 查询来根据关系条件进行查询。
完成所有查询并开始工作后,最后要做的是在我的一些查询中包含 softDeleted 记录(在特定日期后删除)的选项 - 这突出了一些问题。
例如,我可能有一个查询,它通过预先加载必要的数据开始如下:
public function query()
{
$this->query = AssetInstance::with('asset.type', 'zoneInstance.type', 'zoneInstance.zone');
)
然后我可能会有一个函数来选择性地优化查询,如下所示:
function filterByZoneInstance($zone_instance_id)
{
$this->query->whereZoneInstanceId($zone_instance_id);
return $this;
}
我可能有另一个函数来进一步优化查询:
public function filterByZoneType($type)
{
$this->query->whereHas('zone_instance', function($q) use($type){
return $q->whereHas('type', function($q2){
return $q2->whereName($type);
});
});
}
public function get()
{
return $this->query->get();
}
所以这一切都很好,我可以这样做:
$this->query()->filterByZoneType('typex')->get();
现在,假设我想包含 softDeleteResults,我可以这样做:
public function includeTrashed()
{
$this->query->withTashed();
return $this;
}
但这并没有影响关系,所以是的,所有 assetInstances(包括软删除都会被拉入)但不是所有 zoneInstances,如果关系(例如 zone_instance已被软删除)。
所以我认为没问题 - 我可以加载与 trashed 的关系:
public function query()
{
$this->query = AssetInstance::with(['asset.type', 'ZoneInstance' => function ($q){
$q->withTrashed();
}, 'zoneInstance.type', 'zoneInstance.zone']);
)
在您应用 whereHas 查询之前,这种方法一直有效,此时使用 Trashed 的预加载被 wherehas 查询覆盖,wherehas 查询执行它自己的预加载(没有 trashed);
我尝试在 whereHas 闭包中应用约束,但它不起作用:
public function filterByZoneType($type)
{
$this->query->whereHas('zone_instance', function($q) use($type){
return $q->whereHas('type', function($q2){
return $q2->whereName($type)->withTrashed();
})->withTrashed();
});
}
此时我决定使用原始查询,不幸的是这有类似的效果,所以例如如果我做这样的事情:
$this->query->whereRaw("asset_instances.`deleted_at` <= '2014-03-11 00:00:00' and (select count(*) from `variable_data_package_instances` where `variable_data_package_instances`.`asset_instance_id` = `asset_instances`.`id` and `variable_data_package_instances`.`deleted_at` <= '2014-03-11 00:00:00')");
我现在看到的是,废弃的 zoneInstances 不再急切加载(来自之前调用的 query() 函数)。
有没有人幸运地使用 eloquent 关系查询带来了垃圾结果?
这个怎么样:
public function query()
{
$this->query = AssetInstance::with(['asset.type', 'ZoneInstance' => function ($q){
$q->withTrashed()->with('type','zone');
}]);
)->get();
}
我注意到以下代码存在同样的问题:
class Reward extends Model
{
/* ... */
public function membership()
{
return $this->belongsTo(Membership::class);
}
/* ... */
}
和
class Membership extends Model
{
use SoftDeletes ;
/* ... */
public function rewards()
{
return $this->hasMany(Reward::class);
}
/* ... */
}
当我想获得与已删除会员资格关联的奖励时,我使用此查询:
Reward::whereHas( ['membership' => function($query){
$query->withTrashed() ;
}] )->get();
但是,它不起作用,因为 "withTrashed" 方法不是作用域(添加约束)而是创建一个新查询:
public static function withTrashed()
{
return (new static)->newQueryWithoutScope(new SoftDeletingScope);
}
所以,我目前找到的唯一解决方案是使用其他关系:
class Reward extends Model
{
/* ... */
public function membershipWithTrashed()
{
return $this->belongsTo(Membership::class)->withTrashed();
}
/* ... */
}
然后:
Reward::has( 'membershipWithTrashed' )->get();
有效。
在我看来,这是一个非常丑陋的解决方案,需要修复 SoftDelete Trait。
Laravel 5.2 已修复此问题。不再需要丑陋的 hack。
我已经使用 Eloquent 构建了一个存储库层。我在表之间有很多复杂的关系,并且能够使用 eloquent 轻松构建所有查询,我非常依赖 WhereHas 查询来根据关系条件进行查询。
完成所有查询并开始工作后,最后要做的是在我的一些查询中包含 softDeleted 记录(在特定日期后删除)的选项 - 这突出了一些问题。
例如,我可能有一个查询,它通过预先加载必要的数据开始如下:
public function query()
{
$this->query = AssetInstance::with('asset.type', 'zoneInstance.type', 'zoneInstance.zone');
)
然后我可能会有一个函数来选择性地优化查询,如下所示:
function filterByZoneInstance($zone_instance_id)
{
$this->query->whereZoneInstanceId($zone_instance_id);
return $this;
}
我可能有另一个函数来进一步优化查询:
public function filterByZoneType($type)
{
$this->query->whereHas('zone_instance', function($q) use($type){
return $q->whereHas('type', function($q2){
return $q2->whereName($type);
});
});
}
public function get()
{
return $this->query->get();
}
所以这一切都很好,我可以这样做:
$this->query()->filterByZoneType('typex')->get();
现在,假设我想包含 softDeleteResults,我可以这样做:
public function includeTrashed()
{
$this->query->withTashed();
return $this;
}
但这并没有影响关系,所以是的,所有 assetInstances(包括软删除都会被拉入)但不是所有 zoneInstances,如果关系(例如 zone_instance已被软删除)。
所以我认为没问题 - 我可以加载与 trashed 的关系:
public function query()
{
$this->query = AssetInstance::with(['asset.type', 'ZoneInstance' => function ($q){
$q->withTrashed();
}, 'zoneInstance.type', 'zoneInstance.zone']);
)
在您应用 whereHas 查询之前,这种方法一直有效,此时使用 Trashed 的预加载被 wherehas 查询覆盖,wherehas 查询执行它自己的预加载(没有 trashed);
我尝试在 whereHas 闭包中应用约束,但它不起作用:
public function filterByZoneType($type)
{
$this->query->whereHas('zone_instance', function($q) use($type){
return $q->whereHas('type', function($q2){
return $q2->whereName($type)->withTrashed();
})->withTrashed();
});
}
此时我决定使用原始查询,不幸的是这有类似的效果,所以例如如果我做这样的事情:
$this->query->whereRaw("asset_instances.`deleted_at` <= '2014-03-11 00:00:00' and (select count(*) from `variable_data_package_instances` where `variable_data_package_instances`.`asset_instance_id` = `asset_instances`.`id` and `variable_data_package_instances`.`deleted_at` <= '2014-03-11 00:00:00')");
我现在看到的是,废弃的 zoneInstances 不再急切加载(来自之前调用的 query() 函数)。
有没有人幸运地使用 eloquent 关系查询带来了垃圾结果?
这个怎么样:
public function query()
{
$this->query = AssetInstance::with(['asset.type', 'ZoneInstance' => function ($q){
$q->withTrashed()->with('type','zone');
}]);
)->get();
}
我注意到以下代码存在同样的问题:
class Reward extends Model
{
/* ... */
public function membership()
{
return $this->belongsTo(Membership::class);
}
/* ... */
}
和
class Membership extends Model
{
use SoftDeletes ;
/* ... */
public function rewards()
{
return $this->hasMany(Reward::class);
}
/* ... */
}
当我想获得与已删除会员资格关联的奖励时,我使用此查询:
Reward::whereHas( ['membership' => function($query){
$query->withTrashed() ;
}] )->get();
但是,它不起作用,因为 "withTrashed" 方法不是作用域(添加约束)而是创建一个新查询:
public static function withTrashed()
{
return (new static)->newQueryWithoutScope(new SoftDeletingScope);
}
所以,我目前找到的唯一解决方案是使用其他关系:
class Reward extends Model
{
/* ... */
public function membershipWithTrashed()
{
return $this->belongsTo(Membership::class)->withTrashed();
}
/* ... */
}
然后:
Reward::has( 'membershipWithTrashed' )->get();
有效。
在我看来,这是一个非常丑陋的解决方案,需要修复 SoftDelete Trait。
Laravel 5.2 已修复此问题。不再需要丑陋的 hack。