学说区别计数

Doctrine Distinct Count

在实体集合上检索 DISTINCT COUNT 的最佳做法是什么?

在此示例实体 (Customer) 中,我与 OrdersoneToMany 关系。

我想统计客户订购了多少销售额和产品:

> select * from orders;
+----------+----------+----------+
| customer | sale_ref | prod_ref |
+----------+----------+----------+
| 1        | sale_1   | prod_1   |
| 1        | sale_1   | prod_2   |
| 1        | sale_2   | prod_1   |
| 1        | sale_3   | prod_3   |
+----------+----------+----------+

> select count(prod_ref) from order where customer = 1;
+-----------------+
| count(prod_ref) |
+-----------------+
| 4               |
+-----------------+


> select count(distinct(sale_ref)) from order where customer = 1;
+-----------------+
| count(prod_ref) |
+-----------------+
| 3               |
+-----------------+

这是代码

use Doctrine\ORM\Mapping as ORM;

class Customer
{

    /**
     * @var \Doctrine\Common\Collections\Collection
     * @ORM\OneToMany(targetEntity="Orders", mappedBy="customer", cascade={"persist", "remove"}, fetch="EXTRA_LAZY")
     */
    protected $orders;

    /**
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getOrders(): \Doctrine\Common\Collections\Collection
    {
        return $this->orders;
    }

    /**
     * @return int
     */
    public function getOrdersProductCount(): int
    {
        return $this->orders->count();
    }

}

class Orders
{

    /**
     * @var Customer $customer
     * @ORM\ManyToOne(targetEntity="Customer", inversedBy="orders")
     */
    protected $customer;

    /**
     * Non-unique sales reference
     * @var string $salesRef
     * @ORM\Column(name="sales_ref", type="string")
     */
    protected $salesRef;

    /**
     * Unique product reference
     * @var string $productRef
     * @ORM\Column(name="product_ref", type="string")
     */
    protected $productRef;

    /**
     * @return Customer
     */
    public function getCustomer(): Customer
    {
        return $this->customer;
    }

    /**
     * @return string
     */
    public function getProductRef(): string
    {
        return $this->productRef;
    }

    /**
     * @return string
     */
    public function getSalesRef(): string
    {
        return $this->salesRef;
    }

}

使用 Customer->getOrdersProductCount() 检索产品数量非常好,据说是 "good practice" 因为它不会在完全加载集合时访问数据库:

https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/tutorials/extra-lazy-associations.html

If you mark an association as extra lazy the following methods on collections can be called without triggering a full load of the collection Collection#count()

但是,在此示例中,Customer 可以有多个产品进行销售 - 其中 salesRef 是非唯一的。检索 salesRefDISTINCT COUNT 的最佳方法是什么?

这 could/should 在实体存储库中处理 class:

class OrdersRepository
{

    public function getSalesCount($customer): int
    {
        return (int)$this->createQueryBuilder('o')
            ->select('COUNT(DISTINCT(o.salesRef))')
            ->where('o.customer = :customer')
            ->setParameter('customer', $customer)
            ->setMaxResults(1)
            ->getQuery()
            ->getSingleScalarResult();
    }

    public function getProductCount($customer): int
    {
        return (int)$this->createQueryBuilder('o')
            ->select('COUNT(o.productRef)')
            ->where('o.customer = :customer')
            ->setParameter('customer', $customer)
            ->setMaxResults(1)
            ->getQuery()
            ->getSingleScalarResult();
    }

}

这有效,但我需要加载 entityManager/CustomerRepository 才能访问这些方法 - 而至少我可以从实体中检索产品计数....

我如何从客户实体中访问不同的销售计数 - 如果有的话?

我考虑过使用 Collection#filter() method and/or looping through the Orders entity to create an array with the salesRef as the key and then using array_unique#count() 但这似乎没有 "right" - 我想我知道答案(使用实体存储库)但是我希望能够从 Customer 实体中访问销售计数 - 什么是最好的 practice/method?

我认为应该这样做,并且是一种更便携的方式。虽然我没有测试它。

    $qb = $this->createQueryBuilder('o');
    return (int)$qb
        ->select($qb->expr()->countDistinct('o.salesRef'))
        ->where('o.customer = :customer')
        ->setParameter('o.customer', $customer)
        ->setMaxResults(1)
        ->getQuery()
        ->getSingleScalarResult();

参考在这里:https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/query-builder.html#the-querybuilder

希望对您有所帮助