Вы можете достичь этого несколькими способами.
let foo = {
bar: 'Hello World'
};
foo.bar;
foo['bar'];
Обозначение скобок особенно мощно, так как оно позволяет вам получить доступ к свойству на основе переменной:
let foo = {
bar: 'Hello World'
};
let prop = 'bar';
foo[prop];
Это может быть расширено до циклизации по каждому свойству объекта. Это может казаться излишним из-за новых конструкций JavaScript, таких как ... из ..., но помогает иллюстрировать прецедент:
let foo = {
bar: 'Hello World',
baz: 'How are you doing?',
last: 'Quite alright'
};
for (let prop in foo.getOwnPropertyNames()) {
console.log(foo[prop]);
}
Оба точечных и скобковых обозначения также работают как ожидалось для вложенных объектов :
let foo = {
bar: {
baz: 'Hello World'
}
};
foo.bar.baz;
foo['bar']['baz'];
foo.bar['baz'];
foo['bar'].baz;
Деструктурирование объекта
Мы могли бы также рассмотреть разрушение объекта как средство доступа к свойству в объекте, но следующим образом:
let foo = {
bar: 'Hello World',
baz: 'How are you doing?',
last: 'Quite alright'
};
let prop = 'last';
let { bar, baz, [prop]: customName } = foo;
// bar = 'Hello World'
// baz = 'How are you doing?'
// customName = 'Quite alright'
Ваш запрос может быть переписан без объединения подзапросов:
SELECT
a.id_cm,
a.type
COUNT(CASE WHEN b.status = 'PENDING' THEN 1 ELSE NULL END) countPending,
COUNT(CASE WHEN b.status = 'FAILED' THEN 1 ELSE NULL END) countFailed,
COUNT( CASE WHEN b.status = 'PROCESSED' THEN 1 ELSE NULL END ) countProcessed
FROM CM AS a
LEFT JOIN CM_PARAM AS b ON a.id_cm = b.id_cm
WHERE a.id_cm = ?1
GROUP BY a.id_cm, a.type
Вам нужно будет добавить обратную сторону ассоциации к Cm
:
@OneToMany(mappedBy = "cm")
private Set<CmParam> params;
(в противном случае, вам потребуется RIGHT JOIN
от CmParam
до Cm
, что-то, что Hibernate не поддерживает)
Запрос Criteria становится следующим:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<? extends Object[]> cq = cb.createQuery(new Object[0].getClass());
Root<Cm> a = cq.from(Cm.class);
Join<Cm, CmParam> b = a.join("params", JoinType.LEFT);
cq.where(cb.equal(a.get("idCm"), cb.parameter(Long.class, "idCm")));
cq.groupBy(a.get("idCm"), a.get("type"));
cq.multiselect(
a.get("idCm"),
a.get("type"),
cb.count(cb.selectCase()
.when(cb.equal(b.get("status"), "PENDING"), 1L)
.otherwise(cb.nullLiteral(Long.class))),
cb.count(cb.selectCase()
.when(cb.equal(b.get("status"), "FAILED"), 1L)
.otherwise(cb.nullLiteral(Long.class))),
cb.count(cb.selectCase()
.when(cb.equal(b.get("status"), "PROCESSED"), 1L)
.otherwise(cb.nullLiteral(Long.class))));
Обратите внимание, что результат имеет тип Object[]
. Если вы хотите использовать свой текущий подход с переходными полями, самый простой способ - добавить соответствующий конструктор в Cm
и использовать метод cb.construct()
:
cq.select(cb.construct(Cm.class, a.get("idCm"), a.get("type"), ...))
Обратите внимание:
[ 1128]params
в Cm
, но у вас все в порядке с INNER JOIN
, вы можете просто использовать вместо них Root<CmParam> b = cq.from(CmParam.class)
и Join<CmParam, Cm> a = b.join("cm")
. Cm
, чем просто cmId
и status
, вам, вероятно, потребуется перечислить их все также в groupBy