有许多通过多对多

ntz*_*tzm 15 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
Run Code Online (Sandbox Code Playgroud)

products并且metrics与有价值的数据透视列具有多对多关系.

deals并且products还有多对多的关系.

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

我目前在我的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);
    });
}
Run Code Online (Sandbox Code Playgroud)

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

它需要是关系格式,因为它们需要为我的用例急切加载.

谢谢你的帮助!

mpu*_*pur 12

如果要拥有自定义关系,可以创建自己的对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();
}
Run Code Online (Sandbox Code Playgroud)

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

此解决方案可以用于查询与方法的关系和对metrics属性的访问.

  • 在Laravel 5.3中,lists方法变为“ pluck”。所以这行应该是$ this-> products-> pluck('metrics') (2认同)

Nic*_*Yap 11

有一个 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
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

需要定义外键的示例:

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


Raf*_*rro 6

这应该可以解决问题:

模型/Product.php 文件:

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

    public function metrics()
    {
        return $this->belongsToMany(Metric::class);
    }
}
Run Code Online (Sandbox Code Playgroud)

模型/Deal.php 文件:

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

Models/Metric.php 文件:

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

从您的控制器:

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

现在您有了产品交易及其相关指标的集合。请参阅嵌套预加载的文档。


Tho*_*een 5

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

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

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

可能的解决方案:

// 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();
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助 :)

在@ntzm 评论后编辑

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

像这样:

return Metric

    ::select('*')

    ->join(...........
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

像这样:

retrun Metric

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

    ->join(....
Run Code Online (Sandbox Code Playgroud)

这将导致类似:

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
            ....
        ]
    ....
)
Run Code Online (Sandbox Code Playgroud)

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