JPA NamedQuery get distinct column - jpa

I want to get an list of distinct City's from my User table. I thought the code below would work but gives an error:
User.java
#Entity
#Table(name="user_info")
...
#NamedQuery(name = "User.all.cities", query = "SELECT distinct u.city FROM User u"),
...
#embedded
private City city;
UserBusinessLogic.java:
...
TypedQuery<City> typedQuery = entityManager.createNamedQuery("User.all.cities",User.class);
List<City> names = typedQuery.getResultList();
...
It gives: type mismatch can not convert List to List. I tried two get first user then on getResult a City but same error one line below.
I see some examples but not really tell how to get it with correct code just the SQL syntax.
Thanks for your help
Jess

The first thing which doesn't look good is that you ask for City objects but declare to get User's.
You have:
#NamedQuery(name = "User.all.cities",
query = "SELECT distinct u.city FROM User u"),
TypedQuery<City> typedQuery =
entityManager.createNamedQuery("User.all.cities", User.class);
Where it should be:
TypedQuery<City> typedQuery =
entityManager.createNamedQuery("User.all.cities", City.class);

The code that works is:
results = getJpaTemplate().execute(new JpaCallback<List<City>>() {
#Override
public List<City> doInJpa(EntityManager em) throws PersistenceException {
TypedQuery<City> query = em.createNamedQuery("User.all.cities", City.class);
return query.getResultList() ;
}
}) ;

Related

How can i ignore: PSQLException: The column name clothStyle was not found in this ResultSet

I created a a query to only get 4 items from a row in a table which does not include the column cloth style, so i understand why i get the error, but how can i tell Spring Jpa or JPA it is on purpose. and i just want the id, name and color table ?
this is my code:
#RequestMapping(value = "/query/material",method = RequestMethod.GET)
public String QueryMaterialTable(HttpServletRequest request){
DataTableRequest<Material> dataTableInRQ = new DataTableRequest<Material>(request);
PaginationCriteria pagination = dataTableInRQ.getPaginationRequest();
String baseQuery = "SELECT id as id, time as time, name as name, color as color, price as price, (SELECT COUNT(1) FROM MATERIAL) AS totalrecords FROM MATERIAL";
String paginatedQuery = AppUtil.buildPaginatedQuery(baseQuery, pagination);
System.out.println(paginatedQuery);
Query query = entityManager.createNativeQuery(paginatedQuery, Material.class);
#SuppressWarnings("unchecked")
List<Material> materialList = query.getResultList();
DataTableResults<Material> dataTableResult = new DataTableResults<Material>();
dataTableResult.setDraw(dataTableInRQ.getDraw());
dataTableResult.setListOfDataObjects(materialList);
if (!AppUtil.isObjectEmpty(materialList)) {
dataTableResult.setRecordsTotal(String.valueOf(materialList.size())
);
if (dataTableInRQ.getPaginationRequest().isFilterByEmpty()) {
dataTableResult.setRecordsFiltered(String.valueOf(materialList.size()));
} else {
dataTableResult.setRecordsFiltered(String.valueOf(materialList.size()));
}
}
return new Gson().toJson(dataTableResult);
}
If I got the question right, your problem is with the following two lines:
Query query = entityManager.createNativeQuery(paginatedQuery, Material.class);
List<Material> materialList = query.getResultList();
You have various options to fix this:
provide a complete column list, i.e. provide the missing column in the SQL statement and just make them NULL;
Don't use Material but a new class that has the matching attributes.
Don't use a native query but JPQL and a constructor expression.
Use a ResultTransformer.
Use Spring Data and a Projection.
Use a Spring JdbcTemplate.

How to use mongodb query in hibernate OGM?

I want to find only the username field in my Registration collection
I am using the following query
db.Registration.find( {"username":"abcd"}, {username:1, _id:0} )
How will I write this query in hibernate?
If your entity looks like this:
#Entity
class Registration {
#Id
String id;
String username:
}
This should work:
String query = "FROM Registration r WHERE r.username = :username ORDER by r.username ASC, r.id DESC"
List<Registration> results = entityManager.createQuery( query )
.setParameter("username", "abcd")
.getResultList()
or
Registration results = entityManager.createQuery( query )
.setParameter("username", "abcd")
.getSingleResult()
You can also use native queries but I will let you to the documentation: https://docs.jboss.org/hibernate/ogm/5.4/reference/en-US/html_single/#ogm-mongodb-queries-native
You'll need to annotate the (none PK) columns you want to retrieve in the Entity with:
#Column(name = "username")

JPQL: Parameter with that position [1] did not exist

I am working with JPA and JPQL. Using a JPQL I would like to fetch join a collection that is an attribute of a "main" entity rent. Here is my source code:
public Rent getRentWithAllDetails(Rent rent) {
Query queryString = em.createQuery(" select r from Rent r JOIN FETCH r.rentables where r.id = :rid").setParameter(1, rent.getId());
List <Rent> resultList = queryString.getResultList();
return resultList.get(0);
}
and this is the exception I recieve:
Caused by: java.lang.IllegalArgumentException: Parameter with that position [1] did not exist
at org.hibernate.jpa.spi.BaseQueryImpl.findParameterRegistration(BaseQueryImpl.java:518) [hibernate-entitymanager-4.3.7.Final.jar:4.3.7.Final]
at org.hibernate.jpa.spi.BaseQueryImpl.setParameter(BaseQueryImpl.java:674) [hibernate-entitymanager-4.3.7.Final.jar:4.3.7.Final]
at org.hibernate.jpa.spi.AbstractQueryImpl.setParameter(AbstractQueryImpl.java:198) [hibernate-entitymanager-4.3.7.Final.jar:4.3.7.Final]
at org.hibernate.jpa.spi.AbstractQueryImpl.setParameter(AbstractQueryImpl.java:49) [hibernate-entitymanager-4.3.7.Final.jar:4.3.7.Final]
Could someone help me, please?
You are using a named parameter, so you should bind a parameter by that name while creating your query:
String sql = "select r from Rent r JOIN FETCH r.rentables where r.id = :rid";
Query queryString = em.createQuery(sql)
.setParameter("rid", rent.getId());
List<Rent> resultList = queryString.getResultList();
Please change your code to:
public Rent getRentWithAllDetails(Rent rent) {
Query queryString = em.createQuery(" select r from Rent r JOIN FETCH r.rentables where r.id = :rid").setParameter("rid", rent.getId());
List <Rent> resultList = queryString.getResultList();
return resultList.get(0);
}
if rid is repeated multiple times, you can use 0,1..etc accordingly, otherwise use the parameter name itself.

QueryDsl - OR statement not working

I have the following QueryDSL query:
QCustomer customer = QCustomer.customer;
BooleanBuilder builder = new BooleanBuilder();
builder.or(customer.person.name.containsIgnoreCase(query));
builder.or(customer.company.name.containsIgnoreCase(query));
return builder;
And I expect to get results from Persons that contains the name = query and/or Companies that contains the query parameter. But I get nothing.
This is my Customer class mapping:
#OneToOne(orphanRemoval = false, optional = true, cascade = CascadeType.ALL)
private Company company;
#OneToOne(orphanRemoval = false, optional = true, cascade = CascadeType.ALL)
private Person person;
Did someone knows what I'm missing here?
I expect to get a query like this:
select o
from Customer
where o.person.name like '%:name%' or o.company.name like '%:name%'
This is the generated query:
select
count(customer0_.uid) as col_0_0_
from
Customer customer0_
cross join
Person person1_
cross join
Company company2_
where
customer0_.person_uid=person1_.uid
and customer0_.company_uid = company2_.uid
and (lower(person1_.name) like ? escape '!' or lower(company2_.name) like ? escape '!') limit ?
It uses a count because it's the first query that Spring Data use to paginate the result.
The query looks ok. Most probably you get wrong results because the implicit property based joins make the joins inner joins.
Using left joins you might get the results you need.
QPerson person = QPerson.person;
QCompany company = QCompany.company;
BooleanBuilder builder = new BooleanBuilder();
builder.or(person.name.containsIgnoreCase(str));
builder.or(company.name.containsIgnoreCase(str));
query.from(customer)
.leftJoin(customer.person, person)
.leftJoin(customer.company, company)
.where(builder);

How do I count the number of rows returned by subquery?

I want to do something like this:
select count(*) from (select ...)
(As it would be in SQL), but in JPA.
Any ideas on how I would do it?
I stumbled upon this issue as well. I would ultimately like to execute the following JPQL:
SELECT COUNT(u)
FROM (
SELECT DISTINCT u
FROM User u
JOIN u.roles r
WHERE r.id IN (1)
)
But this wasn't possible, also not with criteria API. Research taught that this was just a design limitation in JPA. The JPA spec states that subqueries are only supported in WHERE and HAVING clauses (and thus not in the FROM).
Rewriting the query in the following JPQL form:
SELECT COUNT(u)
FROM User u
WHERE u IN (
SELECT DISTINCT u
FROM User u
JOIN u.roles r
WHERE r.id IN (1)
)
using the JPA Criteria API like as follows:
CriteriaQuery<Long> query = cb.createQuery(Long.class);
Root<User> u = query.from(User.class);
Subquery<User> subquery = query.subquery(User.class);
Root<User> u_ = subquery.from(User.class);
subquery.select(u_).distinct(true).where(u_.join("roles").get("id").in(Arrays.asList(1L)));
query.select(cb.count(u)).where(cb.in(u).value(subquery));
Long count = entityManager.createQuery(query).getSingleResult();
// ...
has solved the functional requirement for me. This should also give you sufficient insight into solving your particular functional requirement.
This should do the trick (If you want to use JPA criteria API):
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Long> query = cb.createQuery(Long.class);
Root<Entity> root = query.from(Entity.class);
//Selecting the count
query.select(cb.count(root));
//Create your search criteria
Criteria criteria = ...
//Adding search criteria
query.where(criteria);
Long count = getEntityManager().createQuery(query).getSingleResult();
On the other hand, if you want to use JP-QL, the following code should do the trick:
//Add the where condition to the end of the query
Query query = getEntityManager().createQuery("select count(*) from Entity entity where...")
Long count = query.getSingleResult();
Use the following snippet to count rows for a given Criteria Query:
public static Query createNativeCountQuery(EntityManager em, CriteriaQuery<?> criteriaQuery) {
org.hibernate.query.Query<?> hibernateQuery = em.createQuery(criteriaQuery).unwrap(org.hibernate.query.Query.class);
String hqlQuery = hibernateQuery.getQueryString();
QueryTranslatorFactory queryTranslatorFactory = new ASTQueryTranslatorFactory();
QueryTranslator queryTranslator = queryTranslatorFactory.createQueryTranslator(
hqlQuery,
hqlQuery,
Collections.emptyMap(),
em.getEntityManagerFactory().unwrap(SessionFactoryImplementor.class),
null
);
queryTranslator.compile(Collections.emptyMap(), false);
String sqlCountQueryTemplate = "select count(*) from (%s)";
String sqlCountQuery = String.format(sqlCountQueryTemplate, queryTranslator.getSQLString());
Query nativeCountQuery = em.createNativeQuery(sqlCountQuery);
Map<Integer, Object> positionalParamBindings = getPositionalParamBindingsFromNamedParams(hibernateQuery);
positionalParamBindings.forEach(nativeCountQuery::setParameter);
return nativeCountQuery;
}
private static Map<Integer, Object> getPositionalParamBindingsFromNamedParams(org.hibernate.query.Query<?> hibernateQuery) {
Map<Integer, Object> bindings = new HashMap<>();
for (var namedParam : hibernateQuery.getParameterMetadata().getNamedParameters()) {
for (int location : namedParam.getSourceLocations()) {
bindings.put(location + 1, hibernateQuery.getParameterValue(namedParam.getName()));
}
}
return bindings;
}