简体   繁体   English

休眠条件-基于一对多关系中的字段限制数据

[英]Hibernate Criteria - Restricting Data Based on Field in One-to-Many Relationship

I need some hibernate/SQL help, please. 我需要一些休眠/ SQL帮助。 I'm trying to generate a report against an accounting database. 我正在尝试针对会计数据库生成报告。 A commission order can have multiple account entries against it. 佣金订单可以有多个针对其的帐户条目。

        class CommissionOrderDAO {
            int id
            String purchaseOrder
            double bookedAmount
            Date customerInvoicedDate
            String state
            static hasMany = [accountEntries: AccountEntryDAO]
            SortedSet accountEntries

            static mapping = {
                version false
                cache usage: 'read-only'
                table 'commission_order'
                id column:'id', type:'integer'
                purchaseOrder column: 'externalId'
                bookedAmount column: 'bookedAmount'
                customerInvoicedDate column: 'customerInvoicedDate'
                state column : 'state'
                accountEntries sort : 'id', order : 'desc'
            }
            ...
        }

        class AccountEntryDAO implements Comparable<AccountEntryDAO> {
            int id
            Date eventDate
            CommissionOrderDAO commissionOrder
            String entryType
            String description
            double remainingPotentialCommission

            static belongsTo = [commissionOrder : CommissionOrderDAO]

            static mapping = {
                version false
                cache usage: 'read-only'
                table 'account_entry'
                id column:'id', type:'integer'
                eventDate column: 'eventDate'
                commissionOrder column: 'commissionOrder'
                entryType column: 'entryType'
                description column: 'description'
                remainingPotentialCommission formula : SQLFormulaUtils.AccountEntrySQL.REMAININGPOTENTIALCOMMISSION_FORMULA
            }

            ....
        }   

The criteria for the report is that the commissionOrder.state==open and the commissionOrder.customerInvoicedDate is not null. 该报告的标准是:missionOrder.state == open,并且CommissionOrder.customerInvoicedDate不为null。 And the account entries in the report should be between the startDate and the endDate and with remainingPotentialCommission > 0. 并且报表中的帐户条目应在startDate和endDate之间,且剩余的PotentialCommission> 0。

I'm looking to display information on the CommissionOrder mainly (and to display account entries on that commission order between the dates), but when I use the following projection: 我希望主要在CommissionOrder上显示信息(并在日期之间显示该委托单上的帐户条目),但是当我使用以下预测时:

        def results = accountEntryCriteria.list {
            projections {
                like ("entryType", "comm%")
                ge("eventDate", beginDate)
                le("eventDate", endDate)
                gt("remainingPotentialCommission", 0.0099d)
                and {
                  commissionOrder {
                    eq("state", "open") 
                    isNotNull("customerInvoicedDate")
                  }
                }
             }
            order("id", "asc")
        }   

I get the correct accountEntries with the proper commissionOrders, but I'm going in backwards: I have loads of accountEntries which can reference the same commissionOrder. 我得到了具有正确的CommissionOrders的正确accountEntries,但是我倒向了:我有很多accountEntries,它们可以引用相同的CommissionOrder。 Aut when I look at the commissionOrders that I've retrieved, each one has ALL its accountEntries not just the accountEntries between the dates. 当我查看检索到的佣金订单时,每个订单都有其所有accountEntries,而不仅仅是两个日期之间的accountEntries。

I then loop through the results, get the commissionOrder from the accountEntriesList, and remove accountEntries on that commissionOrder after the end date to get the "snapshot" in time that I need. 然后,我遍历结果,从accountEntriesList中获取佣金订单,并在结束日期之后删除该佣金订单上的accountEntries,以便及时获得所需的“快照”。

def getCommissionOrderListByRemainingPotentialCommissionFromResults(results, endDate) {
    log.debug("begin getCommissionOrderListByRemainingPotentialCommissionFromResults")
    int count = 0;
    List<CommissionOrderDAO> commissionOrderList = new ArrayList<CommissionOrderDAO>()
    if (results) {
        CommissionOrderDAO[] commissionOrderArray = new CommissionOrderDAO[results?.size()];
        Set<CommissionOrderDAO> coDuplicateCheck = new TreeSet<CommissionOrderDAO>()
        for (ae in results) {
            if (!coDuplicateCheck.contains(ae?.commissionOrder?.purchaseOrder) && ae?.remainingPotentialCommission > 0.0099d) {
                CommissionOrderDAO co = ae?.commissionOrder
                CommissionOrderDAO culledCO = removeAccountEntriesPastDate(co, endDate)
                def lastAccountEntry = culledCO?.accountEntries?.last()
                if (lastAccountEntry?.remainingPotentialCommission > 0.0099d) {
                    commissionOrderArray[count++] = culledCO
                }
                coDuplicateCheck.add(ae?.commissionOrder?.purchaseOrder)
            }
        }
        log.debug("Count after clean is ${count}")
        if (count > 0) {
            commissionOrderList = Arrays.asList(ArrayUtils.subarray(commissionOrderArray, 0, count))
            log.debug("commissionOrderList size = ${commissionOrderList?.size()}")
        }

    }
    log.debug("end getCommissionOrderListByRemainingPotentialCommissionFromResults")
    return commissionOrderList
}

Please don't think I'm under the impression that this isn't a Charlie Foxtrot. 请不要以为我不是Charlie Foxtrot。 The query itself doesn't take very long, but the cull process takes over 35 minutes. 查询本身不会花费很长时间,但是剔除过程需要35分钟以上。 Right now, it's "manageable" because I only have to run the report once a month. 现在,它是“可管理的”,因为我每个月只需要运行一次报表。

I need to let the database handle this processing (I think), but I couldn't figure out how to manipulate hibernate to get the results I want. 我需要让数据库来处理此处理(我认为),但是我无法弄清楚如何操纵休眠来获取所需的结果。 How can I change my criteria? 如何更改我的标准?

Try to narrow down the bottle neck of that process. 尝试缩小该过程的瓶颈。 If you have a lot of data, then maybe this check could be time expensive. 如果您有大量数据,那么此检查可能会很耗时。

coDuplicateCheck.contains(ae?.commissionOrder?.purchaseOrder)

in Set contains have O(n) complexity. Set中包含 O(n)复杂度。 You can use ie Map to store keys that you would check and then search for "ae?.commissionOrder?.purchaseOrder" as key in the map. 您可以使用ie映射存储要检查的密钥,然后在映射中搜索“ ae?.commissionOrder?.purchaseOrder”作为密钥。

The second thought is that maybe when you're getting ae?.commissionOrder?.purchaseOrder it is always loaded from db by lazy mechanism. 第二个想法是,也许当您获取ae?.commissionOrder?.purchaseOrder时,它总是通过惰性机制从db加载。 Try to turn on query logging and check that you don't have dozens of queries inside this processing function. 尝试打开查询日志记录,并检查此处理功能内部没有数十个查询。

Finally and again I would suggest to narrow down where is the most expensive part and time waste. 最后我建议缩小最昂贵的零件和时间的浪费范围。

This plugin maybe helpful. 这个插件可能有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM