How can i execute sql query like this through Criteria API and org.springframework.data.jpa.domain.Specification?
select b.id from brands b
where b.id not in
(select b.id from brands b
left join brand_categories bc on bc.brand_id = b.id
left join categories c on c.id = bc.category_id
where c.id = :id)
I tried this variant, but it didn't work
public static Specification<Brand> notContains(Long id) {
return (root, query, criteriaBuilder) -> {
Subquery<List> subQuery = query.subquery(List.class);
Root<Brand> subRoot = subQuery.from(Brand.class);
Join<Category, Brand> join = root.join("categories");
subQuery.select(subRoot.get("id"));
subQuery.where(criteriaBuilder.equal(join.get("id"), id));
return root.get("id").in(subQuery).not();
};
}
The problem here is that you just mixed up the Root<Brand> outside and the Root<Brand> in the sub-select query. This causes a different query to occur and the result is incorrect.
If you change your join relation in 'subquery' as below, your code will work:
Join<Category, Brand> join = subRoot.join("categories");
Related
This is SQL Query I have tried to join all the tables using Spring Data JPA. Some please help me out.
SELECT op.id AS "Profile ID",
op.organization_name AS "Organization name",
pav.annotation AS "legacy-sams-acc-id",
ip.subnet AS "CIDR IP range"
FROM profile.profile p
JOIN profile.organization_profile op ON op.id = p.id
JOIN profile.profile_annotation_type pat ON pat.publisher_id = p.supplier_publisher_id
LEFT OUTER JOIN
(SELECT pa.id AS id,
pa.profile_id AS profile_id,
ftpa.annotation AS annotation,
ftpa.free_text_profile_annotation_type_id AS free_text_profile_annotation_type_id
FROM profile.profile_annotation pa
JOIN profile.free_text_profile_annotation ftpa ON ftpa.id = pa.id
) AS pav ON pav.free_text_profile_annotation_type_id = pat.id AND pav.profile_id = p.id
LEFT OUTER JOIN profile.ip_range_identifier ip ON ip.organization_profile_id = op.id
WHERE pat.description = 'legacy-sams-acc-id'
AND p.supplier_publisher_id = 66
ORDER BY op.id ASC
Following will be the corresponding Java class. I'm struck with converting SQL to Java.
public Specification<OrganizationProfile> organizationProfileReportCriteria(Long publisherId) {
return (root, criteriaQuery, criteriaBuilder) -> {
Subquery<Profile> profileSubquery = criteriaQuery.subquery(Profile.class);
Root<Profile> profileRoot = profileSubquery.from(Profile.class);
Join<Profile, OrganizationProfile> profileOrganizationProfileJoin = profileRoot.join("supplierPublisher");
profileSubquery.select(profileRoot)
.where(criteriaBuilder.equal(profileOrganizationProfileJoin, root),
criteriaBuilder.equal(profileRoot.get("supplierPublisher").get("id"), publisherId));
Subquery<ProfileAnnotationType> profileAnnotationTypeSubquery = criteriaQuery.subquery(ProfileAnnotationType.class);
Root<ProfileAnnotationType> profileAnnotationTypeRoot = profileAnnotationTypeSubquery.from(ProfileAnnotationType.class);
Join<ProfileAnnotationType, OrganizationProfile> organizationProfileAnnotationTypeJoin
= profileAnnotationTypeRoot.join("publisher");
profileAnnotationTypeSubquery.select(profileAnnotationTypeRoot)
.where(criteriaBuilder.equal(organizationProfileAnnotationTypeJoin, root),
criteriaBuilder.equal(profileAnnotationTypeRoot.get("publisher").get("id"), publisherId));
Subquery<ProfileAnnotation> profileAnnotationSubquery = criteriaQuery.subquery(ProfileAnnotation.class);
Root<ProfileAnnotation> profileAnnotationRoot = profileAnnotationTypeSubquery.from(ProfileAnnotation.class);
Join<ProfileAnnotation, OrganizationProfile> profileAnnotationOrganizationJoin
= profileAnnotationRoot.join("profile");
profileAnnotationSubquery.select(profileAnnotationRoot)
.where(criteriaBuilder.equal(profileAnnotationOrganizationJoin, root),
criteriaBuilder.equal(profileAnnotationRoot.get("profile").get("supplierPublisher").get("id"), publisherId));
return criteriaBuilder.or(criteriaBuilder.exists(profileSubquery));
};
}
Basically, I'm not sure how to join multiple tables using JPA. Someone, please explain to me how to convert multiple join and Subquery for converting SQL to Java. Basically confusion about profile and Organization profile table.
I am stuck in a situation where I am not able to create a filter on left join between two table.
My query is something like this.
select count(*)
from orders o
left
join payments p
on o.id = p.o_id
where o.uid_id = 1
and p.name = "abc"
I am trying to do left join using criteria query. In criteria query.
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Orders> query = cb.createQuery(Orders.class);
Root<Orders> ordersRoot = query.from(Orders.class);
Join<Orders, Payments> join = ordersRoot.join(JOIN_COLUMN, JoinType.LEFT);
List<Predicate> predicates = new ArrayList<>();
predicates.addAll(getPredicates(cb, ordersRoot)); //this method gives other predicates on order table
query.where(predicates.toArray(new Predicate[predicates.size()]));
query.select(ordersRoot).distinct(true);
TypedQuery<Orders> query = entityManager.createQuery(criteriaQuery);
List<Orders> list = query.getResultList();
This is my criteria Java code.
In this I have not added for this check.
orders and payments table has one to many relationship.
I am new to JPA and I have a Left Join scenario.
I have my native sql query as below and I am using left join to fetch the complete records from V_MONITORING table for st.id = 10001.
I have some null values for id_legislature which also needs to be selected and hence using a left join
select distinct
mv.id_set, mv.id_travel, mv.id_legislature
from
V_MONITORING mv
left join v_set st on mv.id_set = st.id
left join v_travel fg on mv.id_travel = fg.id
left join v_legislature gg on mv.id_legislature = gg.id;
The same thing I am implementing using the JPA criteria query, I am unable to fetch the null records
Below is the code
Predicate predicate = cb.conjunction();
Root<MonitoringBE> mvRoot = criteriaQuery.from(MonitoringBE.class);
mvRoot.fetch(MonitoringBE.id_set, JoinType.LEFT);
mvRoot.fetch(MonitoringBE.id_travel, JoinType.LEFT);
mvRoot.fetch(MonitoringBE.id_legislature, JoinType.LEFT);
final Path<Object> serieneinsatzterminPath= mvRoot.get(MonitoringBE.id_set);
predicate = cb.and(predicate, cb.EqualTo(serieneinsatzterminPath.get(SetBE.GUELTIG_VON_DATUM), startSetDate));
criteriaQuery.multiselect(
mvRoot.get(MonitoringBE.id_travel).alias("id_travel"),
mvRoot.get(MonitoringBE.id_set).alias("id_set"),
mvRoot.get(MonitoringBE.id_legislature).alias("id_legislature"))
.distinct(true).where(predicate);
Can some one guide me.
You have to replace the mvRoot.get(MonitoringBE.id_travel) and others in the multiselect-statement with mvRoot.join(MonitoringBE.id_travel, JoinType.LEFT). Otherwise they will end up in a inner join.
I have a problem with Criteria API (JPA 2.0). I want to write code which returns the same result as query (select count from (select count from ... group by ...)):
SELECT COUNT(*) FROM (
SELECT COUNT(*) FROM a
LEFT JOIN p ON a.id = p.a_id
LEFT JOIN s ON a.id = s.a_id
WHERE ... GROUP BY s.r_id
)
I wrote something like this:
CriteriaBuilder builder = slave.getCriteriaBuilder();
CriteriaQuery<Long> query = builder.createQuery(Long.class);
Subquery<Long> subquery = query.subquery(Long.class);
Root<A> entity = subquery.from(A.class);
Join<A, P> pJoin = entity.join("p", JoinType.LEFT);
Join<A, S> sJoin = entity.join("s", JoinType.LEFT);
subquery.select(builder.count(entity));
subquery.where(/*where predicate*/);
subquery.groupBy(sJoin.get("r"));
query.select(builder.count(subquery));
Long result = slave.createQuery(query).getSingleResult();
But I get the exception:
java.lang.IllegalStateException: No criteria query roots were specified
What am I doing wrong here?
I need a single named query that fulfills below both named query conditions only by setting the Query parameter.
Named Query, to fetch record where "softwareVersion" is null OR softwareVersion matched with the list.
#NamedQuery(name = "getIPDetectionDetailsForPanIndia",
query = "select cssc.css.sapId,
cssc.css.hostName,
cssc.cssGoldenConfiguration.category,
cssc.cssGoldenConfiguration.parameter,
cssc.cssGoldenConfiguration.vendor,
cssc.recommendedValue,
cssc.actualValue,
cssc.cssGoldenConfiguration.id,
cssc.cssGoldenConfiguration.information,
cssc.css.softwareVersion,
jioc.name,
cssc.cssGoldenConfiguration.impact,
cssc.cssGoldenConfiguration.command
from CssComplianceDetail cssc
join cssc.css c
left join c.cluster club
left join clus.jiocenter jioc
where cssc.cssGoldenConfiguration.impact in (:impactType)
and cssc.cssGoldenConfiguration.category in (:category)
and TO_CHAR(cssc.creationDate, 'yyyy-MM-dd') = TO_CHAR(:date, 'yyyy-MM-dd')
and (cssc.css.softwareVersion in (:softwareVersion)
or cssc.css.softwareVersion is null)";
Named Query, to fatch record where "softwareVersion" matched with the list only, no need to fatch null softwareVersion.
#NamedQuery(name = "getIPDetectionDetailsForPanIndiaAcceptNull",
query = "select cssc.css.sapId,
cssc.css.hostName,
cssc.cssGoldenConfiguration.category,
cssc.cssGoldenConfiguration.parameter,
cssc.cssGoldenConfiguration.vendor,
cssc.recommendedValue,
cssc.actualValue,
cssc.cssGoldenConfiguration.id,
cssc.cssGoldenConfiguration.information,
cssc.css.softwareVersion,
jioc.name,
cssc.cssGoldenConfiguration.impact,
cssc.cssGoldenConfiguration.command
from CssComplianceDetail cssc
join cssc.css c
left join c.cluster club
left join clus.jiocenter join
where cssc.cssGoldenConfiguration.impact in (:impactType)
and cssc.cssGoldenConfiguration.category in (:category)
and TO_CHAR(cssc.creationDate, 'yyyy-MM-dd') = TO_CHAR(:date, 'yyyy-MM-dd')
and cssc.css.softwareVersion in (:softwareVersion)";
Below is my Java code:
List softwareVersion = new ArrayList();
if(softwareVersion.contains("All")) {
query = getEntityManager().createNamedQuery("getIPDetectionCountForPanIndiaAcceptNull");
} else {
query = getEntityManager().createNamedQuery("getIPDetectionCountForPanIndia");
}
query.setParameter("softwareVersion", softwareVersion);