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

时间:2014-04-08 14:29:01

标签: laravel laravel-4

Laravel 4 Project,使用Eloquent ORM。

我有三个表:客户,订单和产品(+ 1个数据透视表order_product)。客户与订单一对多关联。订单与产品多对多关联。

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

我想在Customer模型上有一个方法来检索客户正在购买的产品列表。

为了更好地理解这一点,假设产品是消耗品。

例如,客户#1可以放置:

  • 产品A,B和C的订单#1;
  • 产品A,C和D的订单#2;
  • 产品C和E的订单#3;

...我想要检索的结果是带有产品A,B,C,D和E的集合。

模型(动态伪编码):

class Product extends Eloquent {

    public function orders()
    {
        return $this->belongsToMany('Order');
    }

}

class Orders extends Eloquent {

    public function customer()
    {
        return $this->belongsTo('Customer', 'customer_id');
    }

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

}

class Customers extends Eloquent {

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

    public function products()
    {
        // What to put here ???
    }

}

4 个答案:

答案 0 :(得分:3)

感谢@ 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();
}

答案 1 :(得分:3)

这是多对多关系,但订单表作为数据透视表。

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

我已经包含了最后两个参数,但是如果您遵循singular_id模式,则可以将它们排除在外。

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

@ deczo的答案可能工作得很好,并且可能性能更高,因为所有的数据缩减都是在数据库中完成的,但这里是一个纯粹的Laravel&#39;毫无疑问,这种方式更具可读性:

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

另外,我在这里对Illuminate\Database\Eloquent\Collection#merge()方法有所了解,它会自动执行DISTINCT类似的事情。如果没有,您将不得不做$collection->unique()类似的事情。