Laravel Eager加载多个多态关系 - 一些软删除,一些不删除

时间:2016-08-15 15:35:48

标签: laravel eloquent

我有几个包含多态字段的模型。这些多边形字段每个包含四个或五个关系,一些是软可删除的,有些则不是。如果你这么做的话,我会陷入“该死的”,如果你不这样做,该死的,并且不确定如何解决。

如果我加载了对eager加载的调用而没有在具有softdeletes的模型上包含trashed:

$deptRisks = \App\DeptRisk::with(['owner', 'riskable']);

我将在那些已被软删除的模型上收到以下错误:

  

尝试获取非对象的属性

如果我使用withTrashed为softdeletes加载:

$deptRisks = \App\DeptRisk::with(['owner', 'riskable' => function ($query) {
        $query->withTrashed();
}]);

我将在那些尚未设置为软删除的模型上收到以下错误:

  

调用未定义的方法   照亮\数据库\查询\生成器:: withTrashed()

我确定我错过了一些明显的东西,但我在旋转。请帮忙。

5 个答案:

答案 0 :(得分:1)

尝试像这样定义您的变形关系(仅在Laravel 5.8中进行了测试)

<?php

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\SoftDeletingScope;

class DeptRisk extends Model {
    function riskable(): MorphTo {
        return $this->morphsTo()->withoutGlobalScope(SoftDeletingScope::class);
    }
}

这将确保返回所有软删除的变形关系。

或者,如果您不想为模型设置全局范围,请在急切的加载回调中删除全局范围,如下所示:

<?php

use App\DeptRisk;
use Illuminate\Database\Eloquent\SoftDeletingScope;

$deptRisks = DeptRisk::with([
    'owner',
    'riskable' => function ($query) {
        $query->withoutGlobalScope(SoftDeletingScope::class);
    }
]);

答案 1 :(得分:0)

我有答案,但不是解决方案。我不相信Laravel目前这是可能的,这是不幸的。

一种解决方法是在关系层面强制执行此操作。 IE有两个独立的关系,有风险且有风险.WithTrashed。然后你可以在加载过程中调用两个,一个没有闭包,另一个没有。这将成功加载所有模型,但有几个缺点,最糟糕的是总是必须创建使用集合的if-check逻辑(一个字段基本上变成两个)。

我选择不使用它,而是返回并将非软删除多态关系变为软删除。这不是一个有效的解决方案,但在两天未能合并之后,它就成功了。

答案 2 :(得分:0)

您可以在定义关系时尝试这样的事情:

library(tidyr)
library(dplyr)

df %>% 
   rownames_to_column(var = 'row') %>% 
   gather(a1:c2, key = 'key', value = 'value') %>% 
   extract(key, into = c('col.base', 'col.index'), regex = '([a-zA-Z]+)([0-9]+)') %>% 
   group_by(row, col.base) %>% 
   summarize(.sum = sum(value)) %>%
   spread(col.base, .sum) %>% 
   bind_cols(df, .) %>% 
   select(-row)

答案 3 :(得分:0)

我也尝试了建议的解决方案

public function riskable() {
    $builder = $this->morphTo();

    if (method_exists($builder, 'withTrashed')) {
        $builder->withTrashed();
    }

    return $builder;
}

不幸的是,$ builder不是实际的模型,因此我无法检查withTrashed方法。

在5.4上,php 7.1是我发现的最优雅的解决方案,是将尝试-> withTrashed封装在try catch中。

public function riskable() {
    $morphTo = $this->morphTo();

    try {
        return $morphTo->withTrashed();
    } catch (\Throwable $e) {
        return $morphTo;
    }

}

在将数据附加到模型时加载多态关系时,我遇到了这个问题。

这对我来说很好。

答案 4 :(得分:0)

我找到了一个对我有用的解决方案,而这里的解决方案对我却不起作用(特别是,将返回值包装在try / catch中没有任何作用)。

我还有更多详细信息where I first posted my answer,但是代码很简单:

use Illuminate\Database\Eloquent\SoftDeletingScope;
//...
public function mySometimesSoftDeletableRelation(){
    return $this->morphTo()->withoutGlobalScope(SoftDeletingScope::class);
}