JPA Custom Query - jpa

I need your help. Basically I want to create a custom query for a view I made that contains most of the data needed by the client. The tricky part here is that the client can specify which columns to include in the search. A sample query would be like:
SELECT distinct s.empno FROM SesdbAllView s
WHERE s.lastname IN :lname AND s.examTaken IN :exam AND
s.training IN :train AND s.trainingFrom BETWEEN :from AND :to AND
s.eligibility IN :elig AND s.profession IN :prof
So I tried translating this to Criteria API but still stuck on how to do it especially in the BETWEEN keywords (where I check a range of a Date and also another for a Integer). When it comes to the IN keywords I'm not sure if I did it correctly as well.
My current code now is:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createTupleQuery();
Root<SesdbAllView> r = cq.from(SesdbAllView.class);
Predicate p = cb.conjunction();
for (Map.Entry<String, Object> param : parameters.entrySet()) {
if (param.getValue() instanceof List) {
Expression<String> exp = r.get(param.getKey());
p = cb.and(p, exp.in((List<String>)param.getValue()));
} else if (param.getValue() instanceof DateFromTo) {
DateFromTo fromTo = (DateFromTo) param.getValue();
p = cb.between(r.get(param.getKey()).as(Date.class),fromTo.getFrom(),fromTo.getTo());
} else if (param.getValue() instanceof IntegerFromTo) {
IntegerFromTo fromTo = (IntegerFromTo) param.getValue();
p = cb.between(r.get(param.getKey()).as(Integer.class),fromTo.getFrom(),fromTo.getTo());
} else {
p = cb.and(p, cb.equal(r.get(param.getKey()), param.getValue()));
}
}
cq.distinct(true);
cq.multiselect(r.get("empNo"))
.where(p);
List<Tuple> result = em.createQuery(cq).getResultList();

Related

Count Criteria joining columns

I'm trying to count the rows of the filter the user uses, when the user wants to list all it works fine, the problem is when they use filters and that makes some joins to work properly.
(This is used for a lazy datatable in jsf)
My criteria code is:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<CarreraHorizontal> cq = cb.createQuery(CarreraHorizontal.class);
Root<CarreraHorizontal> root = cq.from(CarreraHorizontal.class);
CriteriaQuery<Long> cqCount = cb.createQuery(Long.class);
List<Predicate> predicates = new ArrayList<Predicate>();
Join<CarreraHorizontal, Gdp> childJoin = root.join("gdp", JoinType.LEFT);
Join<CarreraHorizontal, Empleado> childJoin2 = root.join("empleado", JoinType.LEFT);
if (!StringUtils.isBlank(grupoTitulacion))
predicates.add(cb.like(root.<String>get("grupoTitulacion"), "%" + grupoTitulacion + "%"));
if(gdp0Bool) {
predicates.add(cb.like(childJoin.<String>get("nombre"), "GDP0"));
if(!StringUtils.isBlank(gdp0Combo))
predicates.add(cb.le(childJoin.<Integer>get("numEscalones"), Integer.parseInt(gdp0Combo)));
}
if(epg6) {
predicates.add(cb.equal(childJoin2.get("progresionEscalon"), epg6));
}
//cq.where(cb.and(predicates.toArray(new Predicate[predicates.size()])));
cqCount.where(cb.and(predicates.toArray(new Predicate[predicates.size()])));
Root<CarreraHorizontal> rootCount = cqCount.from(CarreraHorizontal.class);
CriteriaQuery<Long> a = cqCount.select(cb.count(rootCount));
TypedQuery<Long> res = em.createQuery(a.select(cb.count(rootCount)));
return res.getSingleResult();
My exception is:
Invalid path: 'generatedAlias1.progresionEscalon' [select count(generatedAlias0) from es.valencia.gp.sbch.entity.CarreraHorizontal as generatedAlias0 where generatedAlias1.progresionEscalon=:param0]
I tried everything I found but it's still not working.

Criteria Builder Convert Lower different variant

Everywhere I look I see people using this
predicate =
criteriaBuilder.like(criteriaBuilder.lower(root.get(Product_.prodName)),
wrapper.getProdName());
especially I mean this Product_.prodName. I have no idea what it is, what it does and why I can't use or have it in my context. Here my code which not works:
Look at the line with !nachname.isEmpty
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Telefonbuch> query = builder.createQuery(Telefonbuch.class);
Root<Telefonbuch> root = query.from(Telefonbuch.class);
EntityType<Telefonbuch> model = em.getMetamodel().entity(Telefonbuch.class);
List<Predicate> predicates = new ArrayList<Predicate>();
if (!vorname.isEmpty()) {
Predicate condition = builder.like(root.<String>get("vorname"),"%"+vorname+"%");
predicates.add(condition);
}
if (!nachname.isEmpty()) {
Predicate condition = builder.like(builder.lower(root.get("nachname"),"%"+nachname+"%"));
predicates.add(condition);
}
query.select(root).where(predicates.toArray(new Predicate[predicates.size()]));
eintraege = em.createQuery(query).getResultList();

EF Append to an IQueryable a Where that generates an OR

I'm trying to achieve dynamic filtering on a table. My UI has filters that can be enabled or disabled on demand, and as you can imagine, my query should be able to know when to add filters to the query.
What I have so far is that I check if the filter object has a value, and if it does it adds a where clause to it. Example:
var q1 = DBContext.Table1
if (!string.IsNullOrEmpty(filterModel.SubjectContains))
q1 = q1.Where(i => i.Subject.Contains(filterModel.SubjectContains));
if (filterModel.EnvironmentId != null)
q1 = q1.Where(i => i.EnvironmentId == filterModel.EnvironmentId);
if (filterModel.CreatedBy != null)
q1 = q1.Where(i => i.CreatedByUserId == filterModel.CreatedBy);
var final = q1.Select(i => new
{
IssuesId = i.IssuesId,
Subject = i.Subject,
EnvironmentId = i.EnvironmentId,
CreatedBy = i.CreatedByUser.FullName,
});
return final.ToList();
The code above generates T-SQL that contains a WHERE clause for each field that uses AND to combine the conditions. This is fine, and will work for most cases.
Something like:
Select
IssueId, Subject, EnvironmentId, CreatedById
From
Table1
Where
(Subject like '%stackoverflow%')
and (EnvironmentId = 1)
and (CreatedById = 123)
But then I have a filter that explicitly needs an IssueId. I'm trying to figure out how the EF Where clause can generate an OR for me. I'm looking something that should generate a Tsql that looks like this:
Select
IssueId, Subject, EnvironmentId, CreatedById
From
Table1
Where
(Subject like '%stackoverflow%')
and (EnvironmentId = 1)
and (CreatedById = 123)
or (IssueId = 10001)
Found a solution for this that doesn't have to do multiple database call and works for me.
//filterModel.StaticIssueIds is of type List<Int32>
if (filterModel.StaticIssueIds != null)
{
//Get all ids declared in filterModel.StaticIssueIds
var qStaticIssues = DBContext.Table1.Where(i => filterModel.StaticIssueIds.Contains(i.IssuesId));
//Let's get all Issues that isn't declared in filterModel.StaticIssueIds from the original IQueryable
//we have to do this to ensure that there isn't any duplicate records.
q1 = q1.Where(i => !filterModel.StaticIssueIds.Contains(i.IssuesId));
//We then concatenate q1 and the qStaticIssues.
q1 = q1.Concat(qStaticIssues);
}
var final = q1.Select(i => new
{
IssuesId = i.IssuesId,
Subject = i.Subject,
EnvironmentId = i.EnvironmentId,
CreatedBy = i.CreatedByUser.FullName,
});
return final.ToList();

JPA Criteria api query fails while JPQL goes through

I'm using JPA to manage my persistency layer.
One of my my Criteria API throws an exception. I re-wrote it in JPQL and it works just fine so I guess I missed something in my criteria api version.
Here it is, my criteria api query:
public FoodItemTagsOverrideRule findByFoodItemIdAndType(long foodItemId, RuleTypes ruleType) {
CriteriaQuery<Rule> c = getCriteriaQuery();
Root<Rule> rule =
c.from(Rule.class);
Predicate foodItemIdCondition =
cb.equal(rule.get(Rule_.foodItemId), foodItemId);
Predicate typeCondition =
cb.equal(rule.get(Rule_.ruleType),
ruleType.toString());
c.where(foodItemIdCondition, typeCondition);
TypedQuery<Rule> q =
entityManager.createQuery(c);
List<Rule> result = q.getResultList();
if (result.isEmpty()) {
return null;
}
return result.get(0);
}
The JPQL version that works just fine:
public Rule findByFoodItemIdAndType(long foodItemId, RuleTypes ruleType) {
TypedQuery<Rule> query = getEntityManager().createQuery(
"SELECT rule " + "FROM " + Rule.class.getSimpleName() + " rule " + "WHERE rule.foodItemId = :foodItemId "
+ "AND rule.ruleType = :ruleType", Rule.class);
query.setParameter("foodItemId", foodItemId);
query.setParameter("ruleType", ruleType.toString());
List<Rule> result = query.getResultList();
if (result.isEmpty()) {
return null;
}
return result.get(0);
}
Can you see a difference there? Did I put something wrong in the criteria api query?
Thakns!
You can try the below code. I tried to fit to your code, you can alter accordingly.
CriteriaBuilder qb = em.getCriteriaBuilder();
CriteriaQuery cq = qb.createQuery();
Root<Rule> rule = cq.from(Rule.class);
List<Predicate> predicates = new ArrayList<Predicate>();
predicates.add(qb.equal(rule.get("foodItemId"), foodItemId));
predicates.add(qb.equal(rule.get("ruleType"), ruleType));
cq.select(rule).where(predicates.toArray(new Predicate[]{}));
em.createQuery(cq).getResultList();
Edit : For type-safe predicate definition
predicates.add(qb.equal(rule.get(Rule_.foodItemId), foodItemId));
predicates.add(qb.equal(rule.get(Rule_.ruleType), ruleType));

CollectionAttribute testing in JPA CriteriaBuilder

I have a CriteriaBuilder and am trying to create a predicate to restrict results in a CollectionAttribute. I would like to say something like get all entities in this collection where the entity's attribute A equals x. For example, I have lots of People entities. They have a collection of job titles (previous and current) and I'd like to know about all people who have had a title of "banker". Here is an example:
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Object> query = builder.createQuery();
Root<MheAreaLocation> root = query.from(MheAreaLocation.class);
Predicate p2 = builder.equal(root.get(Jobs_.jobs).get(Jobs_.titles), "banker");
TypedQuery<Object> q = em.createQuery(query);
List<Object> resultList = q.getResultList();
...
Any help would be great. I'm struggling to find much about CollectionAttribute and using them in predicates...and I keep getting nulls when I use the join below in the predicate :-( Thanks
This is my actual code:
CriteriaBuilder builder = em.getCriteriaBuilder();
// CriteriaQuery<Tuple> query = builder.createQuery();
CriteriaQuery<Object> query = builder.createQuery();
Root<MheAreaLocation> mheAreaLocationRoot = query.from(MheAreaLocation.class);
CollectionJoin<MheLocation, AtlasLocationGroupMap> join = mheAreaLocationRoot.join(MheAreaLocation_.childLocation).join(MheLocation_.atlasLocationGroupMapCollection);
// .join(AtlasLocationGroupMap_.atlasLocationGroup, JoinType.INNER);
Predicate p1 = builder.equal(mheAreaLocationRoot.get(MheAreaLocation_.parentLocation).get(MheLocation_.mheLocId), "AZP1B");
// Predicate p2 = builder.equal(mheAreaLocationRoot.get(MheAreaLocation_.childLocation).get(MheLocation_.atlasLocationGroupMapCollection).);
Predicate p2 = builder.equal(join.get(AtlasLocationGroupMap_.atlasLocationGroup).get(AtlasLocationGroup_.locationGroupType), "NEXT_STATION");
// query.where(builder.and(e1, e2));
// mheAreaLocationRoot.fetch(MheAreaLocation_.childLocation);
// join.fetch(MheLocation_.atlasLocationGroupMapCollection);
// query.multiselect(mheAreaLocationRoot.get(MheAreaLocation_.parentLocation),
// mheAreaLocationRoot.get(MheAreaLocation_.childLocation));
// query.select(builder.tuple(join.get(AtlasLocationGroupMap_.mheLocation)));
TypedQuery<Object> q = em.createQuery(query);
List<Object> resultList = q.getResultList();
...
Other classes (I can add more if needed):
#StaticMetamodel(MheLocation.class)
public class MheLocation_ {
public static volatile CollectionAttribute<MheLocation, AtlasLocationGroupMap> atlasLocationGroupMapCollection;
public static volatile SingularAttribute<MheLocation, String> mheLocId;
}
Take this example which has classes of Farm and Animal (Farm has a collection<Animal>) and we want to impose a criteria on the name of the Animal. Not exactly the same as yours I think, but may point you in the right direction
CriteriaBuilder qb = emf.getCriteriaBuilder();
CriteriaQuery<Farm> crit = qb.createQuery(Farm.class);
Root<Farm> candidate = crit.from(Farm.class);
candidate.alias("f");
crit.select(candidate);
Metamodel model = emf.getMetamodel();
ManagedType farmType = model.managedType(Farm.class);
Attribute animalAttr = farmType.getAttribute("animals");
Join animalJoin = candidate.join((ListAttribute)animalAttr);
animalJoin.alias("a");
Path nameField = animalJoin.get("name");
Predicate nameEquals = qb.equal(nameField, "Woolly Sheep");
crit.where(nameEquals);
Equates to
SELECT f FROM org.jpox.samples.annotations.one_many.bidir.Farm f JOIN f.animals a WHERE (a.name = 'Woolly Sheep')
HTH