laravel 有很多通过多对多

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37430217/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 13:52:14  来源:igfitidea点击:

Has many through many-to-many

laravellaravel-5laravel-5.2

提问by ntzm

I have the following table layout:

我有以下表格布局:

deals:
- id
- price

products:
- id
- name

deal_product:
- id
- deal_id
- product_id

metrics:
- id
- name

metric_product:
- id
- metric_id
- product_id
- value

productsand metricshave a many-to-many relationship with a pivot column of value.

productsmetrics与值的枢轴列具有多对多关系。

dealsand productsalso have a many-to-many relationship.

deals并且products也是多对多的关系。

I can get metrics for a product with $product->metrics, but I want to be able to get all metrics for all products related to a deal, so I could do something like this: $deal->metrics.

我能指标与产品$product->metrics,但我希望能够得到有关交易的所有产品的所有指标,所以我可以做这样的事情:$deal->metrics

I currently have the following in my Dealmodel:

我目前在我的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);
    });
}

But this doesn't return a relationship, so I cannot eager load it or get related models from it.

但这不会返回关系,因此我无法急切加载它或从中获取相关模型。

It needs to be in relationship format, because they need to be eager loaded for my use case.

它需要采用关系格式,因为它们需要为我的用例预先加载。

Thanks for your help!

谢谢你的帮助!

采纳答案by mpur

If you want to have a custom relation, you can create your own extends to Relation abstract class. For example: BelongsToManyThought.

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

But if you don't want to implement a Relation, I think that it can fulfill your needs :

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

In App\Deal.php, you can combine the solution of @thomas-van-der-veen

在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();
}

You can refer to this postto see how you can simply use nested relations.

您可以参考这篇文章,了解如何简单地使用嵌套关系。

This solution can do the trick for querying relation with method and access to metrics attribute.

这个解决方案可以用来查询与方法的关系和对度量属性的访问。

回答by Nickson Yap

There is a Laravel 5.5 composer package that can perform multi-level relationships (deep)

有一个 Laravel 5.5 composer 包可以执行多级关系(深)

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

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

Example:

例子:

User→ belongs to many → Role→ belongs to many → Permission

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
        );
    }
}

Example if foreign keys need to be defined:

需要定义外键的示例:

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

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

回答by Thomas Van der Veen

I don't have enough rep to post a comment so I'll post an answer instead.

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

A few days ago I posted a similar questionand was able to answer it myself. I think the solution also works for this question.

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

By joining the tables manually and add a where clause you are able to retrieve the desired Metrics.

通过手动加入表并添加 where 子句,您可以检索所需的指标。

Possible solution:

可能的解决方案:

// 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();

Hope this helps :)

希望这可以帮助 :)

Edit after @ntzm comment

在@ntzm 评论后编辑

If you only need some properties of the metrics table and none of the Model functionalities you can add a select('*') before the joins.

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

Like this:

像这样:

return Metric

    ::select('*')

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

It will return a Metric model with all the attributes of the joined tables.

它将返回一个包含连接表的所有属性的度量模型。

This example will return an object like:

此示例将返回一个对象,如:

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

Since there are a lot of columns with the same name you won't be able to access these values. However you can multiple selects and rename the columns in your results.

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

Like this:

像这样:

retrun Metric

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

    ->join(....

This will result in something like:

这将导致类似:

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

I hope this will solve something :) Of course there are much cleaner ways to solve your problem.

我希望这能解决一些问题 :) 当然,有更简洁的方法可以解决您的问题。

回答by Rafael Berro

This should do the trick:

这应该可以解决问题:

The Models/Product.php file:

Models/Product.php 文件:

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

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

the Models/Deal.php file:

Models/Deal.php 文件:

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

the Models/Metric.php file:

Models/Metric.php 文件:

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

From your controller:

从您的控制器:

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

Now you have a collection of deals with products, and their related metrics. See the docsfor nested eager loading.

现在您拥有了一系列与产品及其相关指标的交易。请参阅嵌套预加载的文档

回答by crabbly

There is no "Many to Many Through" method available.

没有可用的“多对多通过”方法。

To get all Metrics available in all Products for a certain Deal, create a getter to Eager Load all Products and Metrics for the Deal, and leverage Laravel's Collections methods.

要获取某个 Deal 的所有产品中的所有 Metrics,请创建一个 getter 来 Eager Load all Products and Metrics for the Deal,并利用 Laravel 的 Collections 方法。

In your Dealmodel:

在您的Deal模型中:

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

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

You can then get the metrics for a Deal with $deal->getMetrics()

然后,您可以获取交易的指标 $deal->getMetrics()

This will return a Collection of Metrics objects, which should be exactly what you are looking for.

这将返回度量对象的集合,这应该正是您要查找的对象。

回答by Misa Kovic

In case anyone is still researching this, check out this package I recently developed. It provides you with a belongsToManyThrough()relationship and is super easy to install and use :)

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

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

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

回答by Zeyad Mounir

In case someone still needs it:

如果有人仍然需要它:

First you will eager load products and metrics

首先,您将渴望加载产品和指标

$deals->with('products.metrics');

in deal model

在交易模式

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

now you can get all metrics of products of a deal by:

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

$deal->metrics