【问题标题】:Laravel - Making a HasManyThrough Relationship provide a unique collectionLaravel - 建立 HasManyThrough 关系提供了一个独特的集合
【发布时间】:2019-04-13 10:25:06
【问题描述】:

我在让 hasManyThrough 工作时遇到问题:

public function deliveryContainers() : HasManyThrough
{
    return $this->hasManyThrough(
        DeliveryContainer::class, // Final
        StockMovement::class, // Intermediate
        'product_id', // Foreign key on Intermediate
        'id', // Foreign key on Final
        'product_id', // Local key on Current
        'location_id' // Local key on Intermediate
    )->where('delivery_id', $this->delivery_id);
}

由于 stockMovements 表返回多个结果,我生成的交付容器集合包含重复条目。如果我能以某种方式在中间表查询上放置一个组/唯一组,那么这将得到解决。

我可以使用以下方法获得一个包含正确的 deliveryContainers 的集合:

public function deliveryContainers()
{
    return $this->hasMany(StockMovement::class, 'entity_id', 'delivery_id')
        ->with('deliveryContainer')
        ->where('product_id', $this->product_id)
        ->get()
        ->unique('location_id');
}

但是,要访问 deliveryContainer,我现在有以下内容:

foreach($this->deliveryContainers() as $row){
    $row->deliveryContainer->id;    
}

还有我想要的……

foreach($this->deliveryContainers() as $row){
    $row->id;
}

有没有什么方法可以将急切加载的关系提升一个级别(如果可以用来描述它的话),或者甚至更好地为 hasManyThrough 关系添加某种独特的过滤器?

表结构

delivery_exceptions(这种关系的来源)

  • product_id
  • delivery_id

delivery_containers

  • 身份证
  • delivery_id

stock_movements

  • entity_id(链接到交付 ID)
  • product_id

关系

  • 交付异常属于产品
  • 一个产品有很多库存变动
  • 库存移动属于交货容器
  • 交货例外有许多交货容器...(间接地,通过产品和库存变动的组合)

【问题讨论】:

  • 您的模型到底长什么样,它们的键和其他关系定义是什么?
  • 这些真的是delivery_containers 表上的所有键和外键吗?因为如果是这样,你为什么需要hasManyThrough 关系呢?在delivery_exceptions 上,您有一个delivery_id,您可以在delivery_containers 上再次找到它。所以它对我来说看起来很直接......
  • 交付容器实际上需要与库存移动表的关系才能将交付拆分为交付容器。一个交货有许多交货容器,一个交货容器有许多产品。我正在尝试查找包含交付产品的所有交付容器

标签: php laravel eloquent has-many-through


【解决方案1】:

你的设置非常困难,我不完全确定我是否完全理解了它背后的全部想法(也是因为你在某些地方使用了entity_id 而不是delivery_id)。不过,我还是试了一下。

您定义的hasManyThrough 关系实际上看起来还不错,但我认为有更好的方法来获得结果。但首先让我们看看你们的关系:

                                               3
                            +-------------------------------------+
               4            v                                     |
        +-------------> Delivery <----------+                     |
        |                                   | 1                   |
        +                                   +                     +
DeliveryException +---> Product <---+ StockMovement +---> DeliveryContainer
        +                                                         ^
        +---------------------------------------------------------+
                                      2

作为StockMovement 已经属于DeliveryContainer,而后者又属于Delivery,从StockMovementDelivery(标记为1)的关系对我来说似乎已经过时了。无论如何,要在您的模型上获得关系 2,您可以使用路径 34 来发挥您的优势:

class DeliveryException
{
    public function deliveryContainers(): HasMany
    {
        return $this->hasMany(DeliveryContainer::class, 'delivery_id', 'delivery_id');
    }
}

显然,这将为您提供所有DeliveryContainers,未经Product 过滤。因此我建议添加第二个函数:

public function deliveryContainersByProduct(): HasMany
{
    return $this->deliveryContainers()
        ->whereHas('stockMovements', function ($query) {
             $query->where('product_id', $this->product_id);
        });
}

【讨论】:

  • 哇,非常感谢您为此付出的努力。效果很好!
  • 我实际上在此期间还有其他工作(但您的解决方案更加优雅,我现在要切换到这个)。我的其他解决方案作为另一个答案发布以供参考。
【解决方案2】:

接受的答案要优雅得多,但这也是另一种方法:

public function deliveryContainers1()
{
    return $this->hasManyThrough(
        DeliveryContainer::class, // Final
        StockMovement::class, // Intermediate
        'product_id', // Foreign key on Intermediate
        'id', // Foreign key on Final
        'product_id', // Local key on Current
        'location_id' // Local key on Intermediate
    )
        ->where('delivery_id', $this->delivery_id)
        ->distinct();
}

【讨论】:

  • 我想知道为什么您的解决方案需要distinct() 。没有它,生成的查询也不应该检索重复项。但我会自己尝试一下这个解决方案,反正它看起来很有趣。
  • 我认为这是因为它为每个库存移动获取每个交付容器。虽然库存变动都是独一无二的,但它们反过来又引用了重复的交货容器。
  • 我不这么认为。因为如果您有三个模型ABC,其中A 有很多BB 有很多C,您还可以创建一个关系说A 有许多CB。在这种情况下,创建的 sql 查询将如下所示(sql server 语法):select * from [c] inner join [b] on [b].[id] = [c].[b_id] where [b].[a_id] = ??A 实例的id 的占位符)。所以实际上不可能两次检索相同的模型。但当然,这种关系比你的更直接......
猜你喜欢
  • 2016-01-22
  • 2018-07-24
  • 2018-10-18
  • 2023-03-09
  • 1970-01-01
  • 2020-10-14
  • 1970-01-01
  • 1970-01-01
  • 2018-03-08
相关资源
最近更新 更多