Laravel larvel:一对多对多,检索distinct()值

Laravel larvel:一对多对多,检索distinct()值,laravel,laravel-4,Laravel,Laravel 4,Laravel 4项目,使用雄辩的ORM 我有三个表:客户、订单和产品(+1个数据透视表order\U product)。客户被一对多链接到订单。订单与多对多产品相关联 Customers 1-->N Orders N<-->N Products 我想不出这种简单的关系方法,但这里有一个解决方法: $productsIds = DB::table('customers') ->leftJoin('orders', 'orders.customer_id

Laravel 4项目,使用雄辩的ORM

我有三个表:客户、订单和产品(+1个数据透视表order\U product)。客户被一对多链接到订单。订单与多对多产品相关联

Customers  1-->N  Orders  N<-->N   Products

我想不出这种简单的关系方法,但这里有一个解决方法:

$productsIds = DB::table('customers')
    ->leftJoin('orders', 'orders.customer_id', '=', 'customers.id')
    ->join('order_item', 'order_item.order_id', '=', 'orders.id')
    ->leftJoin('items', 'order_item.item_id' , '=', 'items.id')
    ->distinct()
    ->get(['items.id']);

$productsIds = array_fetch($productsIds, 'id');

$productsCollection = Product::whereIn('id', $productsIds);

@deczo的答案可能很好,而且可能会更有效,因为所有的数据缩减都是在数据库本身中完成的,但这里有一种“纯Laravel”的方式无疑更具可读性:

use Illuminate\Database\Eloquent\Collection;

class Customer extends Eloquent
{
    ...
    public function products()
    {
        $products = new Collection;
        foreach ($this->orders as $order) {
            $products = $products->merge($order->products);
        }

        return $products;
    }
}
请注意,此方法的行为与普通关系方法不同-要获取结果集合,请调用该方法(即
$products=$customer->products();
),并且不能像使用关系(即不能执行
$products=$customer->products;
)那样将其作为属性访问


此外,我还将继续了解
illumb\Database\elount\Collection\merge()
方法,它会自动执行类似于
的独特操作。如果没有,您将不得不执行
$collection->unique()
类似的操作。

多亏了@deczo的回答,我能够使用一个查询方法来检索项目:

public function items()
{
    $query = DB::table('items')->select('items.*')
        ->join('item_order', 'item_order.component_id', '=', 'items.id')
        ->leftJoin('orders', 'item_order.order_id', '=', 'orders.id')
        ->leftJoin('customers', 'customers.id' , '=', 'orders.customer_id')
        ->where('customers.id', $this->id)
        ->distinct()
        ->orderBy('items.id');

    $eloquent = new Illuminate\Database\Eloquent\Builder( $query );
    $eloquent->setModel( new Item );
    return $eloquent->get();
}

这是一种多对多关系,但使用订单表作为数据透视表

class Customers extends Eloquent {

    public function orders()
    {
        return $this->hasMany('Orders', 'customer_id');
    }

    public function products()
    {
        return $this->belongsToMany('Products', 'orders', 'customer_id', 'product_id');
    }
}
我已经包括了最后两个参数,但是如果您遵循单数的id模式,那么可以忽略它们

可以收到如下不同的产品型号:

public function products()
{
    return $this->belongsToMany('Products', 'orders', 'customer_id', 'product_id')
        ->distinct();
}

您可能能够使用hasManyThrough并以(通常是隐式的)透视表为目标。类似于
return$this->masManyThrough('Order','OrderProduct')->with('Product')
但是如果这不起作用,那么您必须在该方法中执行一些手动操作并返回一个查询。这不会太难(只需按照没有关系便利的方式构建查询),但它不会像标准关系那样漂亮。@alexrussell:我需要为此创建透视表模型吗?另外,我的低层查询系统的技巧也不是很强,你能指出实际的代码吗(也许作为答案)?是的,我认为你需要对数据透视表建模,以便使用我的
->hasManyThrough()->with()
方法,否则Laravel不知道如何关联数据透视表(这是在
hasManyThrough
之后剩下的内容)到
products
表(这是透视表的“hasMany”)。至于另一种方法,9因为
hasManyThrough
方法可能不起作用,我会看看我能为您想出什么。非常感谢,这就是我现在正在做的,很高兴得到确认。据我所知,主要问题是性能(我认为它会生成N+1个查询)。合并实际上返回一个唯一的结果(但未排序)集合,可以使用排序('id')轻松排序。是的,确实如此-不具有性能,但更易于阅读代码,因此这在某种程度上取决于您的数据大小以及您是否能够承受性能影响。感谢@deczo,我将尝试一下。它还帮助我更好地理解DB对象的工作原理:-)我想它只是遗漏了一个->where('customers.id',$this->id).BTW,是否有更好的方法直接从DB对象获取集合?如果我理解正确,这会进行两次查询,在第一次查询之后,我已经拥有了所需的所有内容。是的,对于给定用户,您需要像您提到的那样附加where语句。关于雄辩的集合-从DB query builder,您不会得到雄辩的结果(模型/模型集合),所以在单个查询中执行此操作的唯一方法是从一开始就使用产品模型。尝试查找该查询,如果您需要任何帮助,请告诉我我似乎在一个查询中找到了一种方法:-)然后您应该共享它,这非常棒。谢谢:-)
public function products()
{
    return $this->belongsToMany('Products', 'orders', 'customer_id', 'product_id')
        ->distinct();
}