获取 grails Criteria 查询中的子对象数
Get count of child objects in grails Criteria query
假设一个域class A 有许多Class B 对象。我需要做一个标准查询 returns
- A.id
- A.name
- B.count(与 A 关联的 B 元素数)
- B.last 更新(考虑到我有所有 B 元素的 last_updated 日期,与 A 关联的 B 元素的最新更新日期)
此外,查询应该足够灵活,可以将 conditions/restrictions 添加到 A 和 B 域对象。
目前我已经做到了这一点:
A.createCriteria().list {
createAlias('b','b')
projections{
property('id')
property('gender')
property('dateOfBirth')
count('b.id')
property('publicId')
}
}
但问题是它只有 returns 个对象,而子对象的计数是针对 B 的所有元素,而不仅仅是与 A 关联的元素
最近我在一个类似的场景中,我需要一个查询,其中你的一行将存储一对多关系中的许多计数
但与您的情况不同,我使用 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 中声明一行,然后在 from 子句中声明派生查询,该查询将结果存储在与 main [=28 中声明的同名行中=]
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
我分享的最后一个例子来自 made by the user Aaron Dietz to the 我也制定了
希望对你有用
原来我离解决方案不远,我只需要根据右边的 属性 进行分组,这是子 table 中的外键列 b.a 在这种情况下,下面的工作现在
A.createCriteria().list {
createAlias('b','b')
projections{
property('id')
property('gender')
property('dateOfBirth')
count('b.id')
groupProperty('b.a')
property('publicId')
}
}
在标准中,您需要按 属性 分组,这不是聚合。
尝试以下:
A.createCriteria().list {
createAlias('b','b')
projections{
groupProperty('id','id')
groupProperty('gender','gender')
groupProperty('dateOfBirth','dateOfBirth')
count('b.id','total')
groupProperty('publicId','publicId')
}
}
或者如果你想要一个地图对象列表 return 你可以尝试添加 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')
}
}
希望能帮到你
假设一个域class A 有许多Class B 对象。我需要做一个标准查询 returns
- A.id
- A.name
- B.count(与 A 关联的 B 元素数)
- B.last 更新(考虑到我有所有 B 元素的 last_updated 日期,与 A 关联的 B 元素的最新更新日期)
此外,查询应该足够灵活,可以将 conditions/restrictions 添加到 A 和 B 域对象。 目前我已经做到了这一点:
A.createCriteria().list {
createAlias('b','b')
projections{
property('id')
property('gender')
property('dateOfBirth')
count('b.id')
property('publicId')
}
}
但问题是它只有 returns 个对象,而子对象的计数是针对 B 的所有元素,而不仅仅是与 A 关联的元素
最近我在一个类似的场景中,我需要一个查询,其中你的一行将存储一对多关系中的许多计数
但与您的情况不同,我使用 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 中声明一行,然后在 from 子句中声明派生查询,该查询将结果存储在与 main [=28 中声明的同名行中=]
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
我分享的最后一个例子来自
希望对你有用
原来我离解决方案不远,我只需要根据右边的 属性 进行分组,这是子 table 中的外键列 b.a 在这种情况下,下面的工作现在
A.createCriteria().list {
createAlias('b','b')
projections{
property('id')
property('gender')
property('dateOfBirth')
count('b.id')
groupProperty('b.a')
property('publicId')
}
}
在标准中,您需要按 属性 分组,这不是聚合。
尝试以下:
A.createCriteria().list {
createAlias('b','b')
projections{
groupProperty('id','id')
groupProperty('gender','gender')
groupProperty('dateOfBirth','dateOfBirth')
count('b.id','total')
groupProperty('publicId','publicId')
}
}
或者如果你想要一个地图对象列表 return 你可以尝试添加 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')
}
}
希望能帮到你