【问题标题】:Doctrine QueryBuilder summary functions in Symfony entity repositories?Symfony 实体存储库中的 Doctrine QueryBuilder 汇总函数?
【发布时间】:2016-05-31 08:28:05
【问题描述】:

有没有办法可以在 Doctrine 的 QueryBuilder 中使用 min()(或等效项)?

我正在处理的页面显示了当前(或模拟)用户的发票表。他们的每张发票都有一行,并且有任何相关付款的嵌套可折叠行(见下图)

我的问题是,在我的树枝模板中,我需要能够在发票级别识别是否有任何付款未获批准。如果任何付款未获批准,那么我需要标记付款及其相关的发票行。例如,在下面的示例中,“Invoice #1”是黄色的,因为它有一个嵌套的“Payment #2”记录是黄色的(未批准):

为了在发票级别访问此内容,我一直在尝试通过我的 InvoiceRepository 进行此操作,但我不清楚是否/如何使用 QueryBuilder 来完成此操作。我不知何故需要anyToBeApproved(这不是我的发票实体的属性)可用,并且还包括付款信息:

select a.*, min(b.approved) as anyToBeApproved
from Invoice a
left join Payment b
on a.invoice_id=b.id
where a.member_id=$Uid
group by a.id

我的控制器:

$invoices = $em->getRepository('AppBundle:Invoice')->OutstandingForUser($this->getUser()->getId());

我的查询生成器:

public function OutstandingForUser($Uid)
{
    return $this->createQueryBuilder('i')
        ->select('i')
        ->leftJoin('i.member_id','m')
        ->leftJoin('i.payment_ids','p')
        ->andwhere('m.member_id = :MemberId' )
        ->setParameter('MemberId',$Uid)
        ->getQuery()
        ->getResult();
}

【问题讨论】:

    标签: doctrine-orm doctrine symfony query-builder


    【解决方案1】:

    我不知道为什么还没有回答,但你应该可以很好地使用这些聚合函数。

    在 SELECT 和 GROUP BY 中允许使用以下聚合函数 子句:AVG、COUNT、MIN、MAX、SUM

    查看文档:http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#aggregate-functions

    你可以在querybuilder中使用聚合函数->select() OK。

    我会将您的函数重写为:

    public function OutstandingForUser($Uid)
    {
        return $this->createQueryBuilder('i')
            ->select('i, min(p.approved) as anyToBeApproved')
            ->leftJoin('i.member','m', 'WITH', 'm.member_id = :MemberId') // this works better with not actually constraining your left join, otherwise you might as well just use innerJoin
            ->leftJoin('i.payment','p') 
            ->groupBy('i.id')
            ->setParameter('MemberId',$Uid)
            ->getQuery()
            ->getResult();
    }
    

    这是另一种方法,因为您似乎仍然想要所有发票行。

    将您的 fetch 函数更改为:

    public function OutstandingForUser($Uid)
    {
        return $this->createQueryBuilder('i')
            ->select('i, p, m') // may as well pre-fetch all entities
            ->join('i.member','m') // member is surely mandatory? so no left join required
            ->leftJoin('i.payment','p') // payments may not be present, so left join
            ->where('m.member_id = :MemberId')
            ->setParameter('MemberId',$Uid)
            ->getQuery()
            ->getResult();
    }
    

    然后在您的发票实体中执行类似的操作

        public function hasUnapprovedPayments () {
    
            foreach ($this->getPayments() as $payment) {
    
                if (!$payment->approved()) {
    
                    return true;
                }
            }
    
            return false;
        }
    
        public function hasPayments () {
    
            return !$this->getPayments()->isEmpty(); // assuming doctrine collection
        }
    

    这些函数会非常快,因为您已经在上面的函数中为实体补水了。

    您也可以添加一个类似的 isFullyPaid 方法来循环付款,但我个人会在发票上设置一个布尔值或日期时间,当发票完全支付时设置。

    然后在 twig 中你可以执行以下操作:

        {% for invoice in invoices %}
          {% if invoice.hasUnapprovedPayments %} do something {% endif %}
          {% if invoice.hasPayments %} do something {% endif %}
          {# loop through all your payments etc #}
        {% endfor %}
    

    这应该可以很容易地获得您想要的布局。

    【讨论】:

    • 非常感谢 - 正如你所说,我已经更新了我的 QueryBuilder 并且 min() 正在添加到 Invoice 行中 - 但是 Payment 行正在“分组”出来。我试过->GroupBy('i.id','p.id') 但不幸的是这也不起作用。你知道我需要怎么调整吗?
    • 听起来您无论如何都必须始终获取每张发票。我已经为您添加了另一种方法,因为我会自己解决问题。
    • 太棒了——非常感谢!实体函数是个好主意:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-08
    • 2016-08-18
    • 1970-01-01
    • 2016-05-05
    • 2018-05-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多