Laravel - 使 HasManyThrough 关系提供唯一集合
Laravel - Making a HasManyThrough Relationship provide a unique collection
我在使用 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 table returns 多个结果,我生成的交付容器集合包含重复条目。如果我能以某种方式在中间 table 查询上放置 group/unique 那么这将得到解决。
我可以使用以下方法获取带有正确的 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 关系添加某种独特的过滤器?
Table结构
delivery_exceptions(此关系的来源)
- product_id
- delivery_id
delivery_containers
- id
- delivery_id
stock_movements
- entity_id(链接到送货 ID)
- product_id
关系
- 一个交付异常属于一个产品
- 一个产品有很多stock_movements
- 一个库存变动属于一个交付容器
- 一个交付异常有许多交付容器...(间接地,通过产品和库存移动的组合)
你那里的设置真的很难,我不完全确定我是否理解了它背后的全部想法(也是因为你在某些地方使用 entity_id
而不是 delivery_id
).尽管如此,我还是试了一下。
您定义的 hasManyThrough
关系实际上看起来还不错,但我认为有更好的方法可以得到结果。但首先让我们看看你们的关系:
3
+-------------------------------------+
4 v |
+-------------> Delivery <----------+ |
| | 1 |
+ + +
DeliveryException +---> Product <---+ StockMovement +---> DeliveryContainer
+ ^
+---------------------------------------------------------+
2
因为StockMovement
已经属于DeliveryContainer
,而在return中属于Delivery
,从StockMovement
到[=18的关系=](标记为 1
)对我来说似乎已经过时了。无论如何,要在你的模型上获得关系 2
,你可以使用路径 3
和 4
来发挥你的优势:
class DeliveryException
{
public function deliveryContainers(): HasMany
{
return $this->hasMany(DeliveryContainer::class, 'delivery_id', 'delivery_id');
}
}
显然,这将为您提供未被 Product
过滤的所有 DeliveryContainers
。因此我建议添加第二个函数:
public function deliveryContainersByProduct(): HasMany
{
return $this->deliveryContainers()
->whereHas('stockMovements', function ($query) {
$query->where('product_id', $this->product_id);
});
}
接受的答案要优雅得多,但这也是另一种方法:
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();
}
我在使用 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 table returns 多个结果,我生成的交付容器集合包含重复条目。如果我能以某种方式在中间 table 查询上放置 group/unique 那么这将得到解决。
我可以使用以下方法获取带有正确的 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 关系添加某种独特的过滤器?
Table结构
delivery_exceptions(此关系的来源)
- product_id
- delivery_id
delivery_containers
- id
- delivery_id
stock_movements
- entity_id(链接到送货 ID)
- product_id
关系
- 一个交付异常属于一个产品
- 一个产品有很多stock_movements
- 一个库存变动属于一个交付容器
- 一个交付异常有许多交付容器...(间接地,通过产品和库存移动的组合)
你那里的设置真的很难,我不完全确定我是否理解了它背后的全部想法(也是因为你在某些地方使用 entity_id
而不是 delivery_id
).尽管如此,我还是试了一下。
您定义的 hasManyThrough
关系实际上看起来还不错,但我认为有更好的方法可以得到结果。但首先让我们看看你们的关系:
3
+-------------------------------------+
4 v |
+-------------> Delivery <----------+ |
| | 1 |
+ + +
DeliveryException +---> Product <---+ StockMovement +---> DeliveryContainer
+ ^
+---------------------------------------------------------+
2
因为StockMovement
已经属于DeliveryContainer
,而在return中属于Delivery
,从StockMovement
到[=18的关系=](标记为 1
)对我来说似乎已经过时了。无论如何,要在你的模型上获得关系 2
,你可以使用路径 3
和 4
来发挥你的优势:
class DeliveryException
{
public function deliveryContainers(): HasMany
{
return $this->hasMany(DeliveryContainer::class, 'delivery_id', 'delivery_id');
}
}
显然,这将为您提供未被 Product
过滤的所有 DeliveryContainers
。因此我建议添加第二个函数:
public function deliveryContainersByProduct(): HasMany
{
return $this->deliveryContainers()
->whereHas('stockMovements', function ($query) {
$query->where('product_id', $this->product_id);
});
}
接受的答案要优雅得多,但这也是另一种方法:
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();
}