获取grails中的子对象计数条件查询

时间:2017-12-11 06:53:50

标签: grails gorm

让我们假设一个域类A有许多B类对象。我需要做一个返回

的条件查询
  1. A.id
  2. A.name
  3. B.count(与A相关的B元素的数量)
  4. B.last更新(考虑到我有所有B元素的last_updated日期,与A关联的B元素的最新更新日期)
  5. 此外,查询应该足够灵活,以便为A和B域对象添加条件/限制。 目前我已经达到了这个目标:

    A.createCriteria().list {
        createAlias('b','b')
        projections{
            property('id')
            property('gender')
            property('dateOfBirth')
            count('b.id')
            property('publicId')
        }
    }
    

    但问题是它只返回一个对象而且子对象的数量是针对B的所有元素而不仅仅是与A相关的那些元素

3 个答案:

答案 0 :(得分:1)

最近我遇到了类似的情况,我需要一个查询,其中一行将以多对多关系存储多个计数

但与您的方案不同,我使用native sql queries来解析查询。

解决方案是使用派生表(我不知道如何使用条件查询来实现它们)。

如果您发现它有用,我会与Grails服务中的实现共享代码:

List<Map> resumeInMonth(final String monthName) {
        final session = sessionFactory.currentSession
        final String query = """
            SELECT
                t.id AS id,
                e.full_name AS fullName,
                t.subject AS issue,
                CASE t.status
                    WHEN 'open' THEN 'open'
                    WHEN 'pending' THEN 'In progress'
                    WHEN 'closed' THEN 'closed'
                END AS status,
                CASE t.scheduled
                    WHEN TRUE THEN 'scheduled'
                    WHEN FALSE THEN 'non-scheduled'
                END AS scheduled,
                ifnull(d.name, '') AS device,
                DATE(t.date_created) AS dateCreated,
                DATE(t.last_updated) AS lastUpdated,
                IFNULL(total_tasks, 0) AS tasks
            FROM
                tickets t
                    INNER JOIN
                employees e ON t.employee_id = e.id
                    LEFT JOIN
                devices d ON d.id = t.device_id
                    LEFT JOIN
                (SELECT
                    ticket_id, COUNT(1) AS total_tasks
                FROM
                    tasks
                GROUP BY ticket_id) ta ON t.id = ta.ticket_id
            WHERE
                MONTHNAME(t.date_created) = :monthName
            ORDER BY dateCreated DESC"""
        final sqlQuery = session.createSQLQuery(query)
        final results = sqlQuery.with {
            resultTransformer = AliasToEntityMapResultTransformer.INSTANCE

            setString('monthName', monthName)

            list()
        }

        results
    }

感兴趣的部分是在main select中声明一行,然后在子句中声明派生查询,该查询将结果存储在主select中声明的同名行中

SELECT ...
       total_tasks --Add the count column to your select
FROM ticket t
JOIN (SELECT ticked_id, COUNT(1) as total_tasks
      FROM tasks
      GROUP BY ticked_id) ta ON t.id = ta.ticked_id
...rest of query

我从用户Aaron Dietz向我answer提出的question分享的最后一个例子

我希望它对你有用

答案 1 :(得分:0)

原来我离解决方案还很远,我只需要根据正确的属性进行分组,这是子表中的外键列,在这种情况下是ba,所以现在以下工作< / p>

A.createCriteria().list {
  createAlias('b','b')
  projections{
    property('id')
    property('gender')
    property('dateOfBirth')
    count('b.id')
    groupProperty('b.a')
    property('publicId')
    }
}

答案 2 :(得分:0)

在标准中,您需要按属性进行分组,而不是聚合。
试试以下:

A.createCriteria().list {
    createAlias('b','b')
    projections{
        groupProperty('id','id')
        groupProperty('gender','gender')
        groupProperty('dateOfBirth','dateOfBirth')
        count('b.id','total')
        groupProperty('publicId','publicId')
    }
}

或者如果您想要一个地图对象返回列表,您可以尝试添加resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)

 A.createCriteria().list {
    resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)
    createAlias('b','b')
    projections{
        groupProperty('id','id')
        groupProperty('gender','gender')
        groupProperty('dateOfBirth','dateOfBirth')
        count('b.id','total')
        groupProperty('publicId','publicId')        
    }
}

希望它可以提供帮助