有许多通过多对多

时间:2016-05-25 07:14:32

标签: laravel laravel-5 laravel-5.2

我有以下表格布局:

deals:
- id
- price

products:
- id
- name

deal_product:
- id
- deal_id
- product_id

metrics:
- id
- name

metric_product:
- id
- metric_id
- product_id
- value

productsmetrics与数据透视列有多对多关系。

dealsproducts也有多对多的关系。

我可以获得$product->metrics产品的指标,但我希望能够获得与交易相关的所有产品的所有指标,因此我可以执行以下操作:$deal->metrics。< / p>

我目前在Deal模型中有以下内容:

public function metrics()
{
    $products = $this->products()->pluck('products.id')->all();

    return Metric::whereHas('products', function (Builder $query) use ($products) {
        $query->whereIn('products.id', $products);
    });
}

但是这不会返回关系,所以我不能急于加载它或从中获取相关模型。

它需要处于关系格式,因为它们需要为我的用例加载。

感谢您的帮助!

8 个答案:

答案 0 :(得分:10)

如果您想拥有自定义关系,可以创建自己的对Connections抽象类的扩展。例如:BelongsToManyThought

但是如果你不想实现一个关系,我认为它可以满足你的需求:

在App \ Deal.php中,您可以结合@ thomas-van-der-veen的解决方案

public function metrics()
{
    return Metric

    ::join('metric_product', 'metric.id', '=', 'metric_product.metric_id')

    ->join('products', 'metric_product.product_id', '=', 'products.id')

    ->join('deal_product', 'products.id', '=', 'deal_product.product_id')

    ->join('deals', 'deal_product.deal_id', '=', 'deal.id')

    ->where('deal.id', $this->id);

}


// you can access to $deal->metrics and use eager loading
public function getMetricsAttribute()
{
    if (!$this->relationLoaded('products') || !$this->products->first()->relationLoaded('metrics')) {
        $this->load('products.metrics');
    }

    return collect($this->products->lists('metrics'))->collapse()->unique();
}

您可以参考此post,了解如何使用嵌套关系。

此解决方案可以解决与方法和度量属性访问的关系问题。

答案 1 :(得分:3)

我没有足够的代表发表评论,所以我会发布一个答案。

前几天我发布了一个类似的question并且能够自己回答。我认为该解决方案也适用于这个问题。

通过手动连接表并添加where子句,您可以检索所需的度量标准。

可能的解决方案:

mant

希望这会有所帮助:)

@ntzm评论后编辑

如果您只需要指标表的某些属性而不需要任何模型功能,则可以在连接之前添加选择('*')。

像这样:

// Deal.php
public function metrics()
{
    return Metric

        ::join('metric_product', 'metric.id', '=', 'metric_product.metric_id')

        ->join('products', 'metric_product.product_id', '=', 'products.id')

        ->join('deal_product', 'products.id', '=', 'deal_product.product_id')

        ->join('deals', 'deal_product.deal_id', '=', 'deal.id')

        ->where('deal.id', $this->id);

}

// How to retrieve metrics
$deal->metrics()->get();

// You can still use other functions like (what I needed) pagination
$deal->metrics()->paginate(24);

// Or add more where clauses
$deal->metrics()->where(blablabla)->get();

它将返回一个Metric模型,其中包含已连接表的所有属性。

此示例将返回如下对象:

return Metric

    ::select('*')

    ->join(...........

由于有许多具有相同名称的列,您将无法访问这些值。但是,您可以多次选择并重命名结果中的列。

像这样:

Metric (
    ....
        attributes: [
            id => 0, // From metrics table
            name => 'somename', // Metrics table
            metric_id => 0, // metric_product table
            product_id => 0, // metric_product table
            ....
        ]
    ....
)

这将导致类似:

retrun Metric

    ::select([
        *,
        DB::raw('products.name as product_name'),
        ....
    ])

    ->join(....

我希望这能解决问题:)当然有更简洁的方法来解决你的问题。

答案 2 :(得分:3)

这应该可以解决问题:

Models / Product.php文件:

class Product extends Model
{
    public function deals()
    {
        return $this->belongsToMany(Deal::class);
    }

    public function metrics()
    {
        return $this->belongsToMany(Metric::class);
    }
}

Models / Deal.php文件:

class Deal extends Model
{
    public function products()
    {
        return $this->belongsToMany(Product::class);
    }
}

Models / Metric.php文件:

class Metric extends Model
{
    public function products()
    {
        return $this->belongsToMany(Product::class);
    }
}

来自您的控制器:

class ExampleController extends Controller
{
    public function index()
    {
        $deal = Deal::with('products.metrics')->get();
    }
}

现在您有一系列产品交易及其相关指标。有关嵌套的预先加载,请参阅docs

答案 3 :(得分:2)

有一个Laravel 5.5 Composer软件包,可以执行多级关系(深层)

包装: https://github.com/staudenmeir/eloquent-has-many-deep

示例:

User→属于许多→Role→属于许多→Permission

class User extends Model
{
    use \Staudenmeir\EloquentHasManyDeep\HasRelationships;

    public function permissions()
    {
        return $this->hasManyDeep(
            'App\Permission',
            ['role_user', 'App\Role', 'permission_role'], // Pivot tables/models starting from the Parent, which is the User
        );
    }
}

例如需要定义外键的示例:

https://github.com/staudenmeir/eloquent-has-many-deep/issues/7#issuecomment-431477943

答案 4 :(得分:1)

没有“多对多”的方法。

要为特定交易获取所有产品中的所有指标,请创建一个获取者以获取交易的所有产品和指标,并利用Laravel的集合方法。

Deal模型中:

public function products()
{
    return $this->belongsToMany('App\Product');
}

public function getMetrics()
{
    return $this->products->lists('metrics')->collapse()->values();
}

然后,您可以使用$deal->getMetrics()

获取促销的指标

这将返回一个Metrics对象集合,它应该是您正在寻找的对象。

答案 5 :(得分:0)

如果有人仍然需要它:

首先,您将急切地加载产品和指标

$deals->with('products.metrics');
交易模型中的

public function getMetricsAttribute(){
   return $this->products->pluck('metrics')->collapse();
}

现在您可以通过以下方式获取交易产品的所有指标:

$deal->metrics

答案 6 :(得分:0)

如果有人仍在研究此功能,请查看我最近开发的此程序包。它为您提供了belongsToManyThrough()的关系,并且非常易于安装和使用:)

https://github.com/shomisha/unusual-relationships

答案 7 :(得分:0)

an article by Jarek on SOFTonSOFA改编而成的另一种方法是使用load方法来获得遥远的关系。

在中间设置了HasMany关系(在products模型上使用Metric,在deals模型上使用Product),您可以创建dealsMetric表直接相关:

public function deals()
{
    $this->load([
        // `products` and `deals` are the names of the joining relations
        'products.deals' => function ($query) use ( &$deals ) {
            $deals = $query;
        }
    ]);

    $deals;
}

这适用于任何级别的子关系,并且在缩放以进行更深层的关系嵌套时几乎不会增加混乱。另外,当它返回一个关系时,它使您可以利用急切的加载。