I have an entity (StockKeepingUnit) with NamedNativeQuery:
#NamedNativeQuery(name = StockKeepingUnit.NQ_FINDBY_ARTICLE_AND_SIZE, resultClass = StockKeepingUnit.class, hints = {
#QueryHint(name = "org.hibernate.cacheable", value = "false"),
#QueryHint(name = "org.hibernate.fetchSize", value = "1"),
#QueryHint(name = "org.hibernate.readOnly", value = "true") }, query = "SELECT * "
+ "FROM StockKeepingUnit sku " + "WHERE sku.article = :articleNumber "
+ "AND sku.size = :size " + "AND sku.deleted = 0")
Call in Java:
Query query = em.createNamedQuery(StockKeepingUnit.NQ_FINDBY_ARTICLE_AND_SIZE);
query.setParameter(StockKeepingUnit.NQ_PARAM_ARTICLE_NR, articleNumber);
query.setParameter(StockKeepingUnit.NQ_PARAM_SIZE, size);
return (StockKeepingUnit) query.getSingleResult();
With this query I want only select the sku.stockKeepingUnitNumber and get an Integer-Value as result when I execute this query.
I tried something like this, but this did not work...
#NamedNativeQuery(name = StockKeepingUnit.NQ_FINDBY_ARTICLE_AND_SIZE, resultClass = Integer.class, hints = {
#QueryHint(name = "org.hibernate.cacheable", value = "false"),
#QueryHint(name = "org.hibernate.fetchSize", value = "1"),
#QueryHint(name = "org.hibernate.readOnly", value = "true") }, query = "SELECT sku.stockKeepingUnitNumber "
+ "FROM StockKeepingUnit sku " + "WHERE sku.article = :articleNumber "
+ "AND sku.size = :size " + "AND sku.deleted = 0")
Call in Java:
Query query = em.createNamedQuery(StockKeepingUnit.NQ_FINDBY_ARTICLE_AND_SIZE);
query.setParameter(StockKeepingUnit.NQ_PARAM_ARTICLE_NR, articleNumber);
query.setParameter(StockKeepingUnit.NQ_PARAM_SIZE, size);
return (Integer) query.getSingleResult();
Can anybody help me?
I solved the problem wit ResultSetMapping :-)
#SqlResultSetMapping(name = StockKeepingUnit.NQ_FIND_ONLY_SKU, columns = {
#ColumnResult(name = StockKeepingUnit.NQ_RESULT_SKU_NAME)}
in NamedQuery you can refer to this mapping with the attribute
#NamedNativeQuery(name = StockKeepingUnit.NQ_FINDBY_ARTICLE_AND_SIZE, resultSetMapping = StockKeepingUnit.NQ_FIND_ONLY_SKU, query = "SELECT sku.stockKeepingUnitNumber as "
+ StockKeepingUnit.NQ_RESULT_SKU_NAME
+ " FROM StockKeepingUnit sku " + "WHERE sku.article = :articleNumber "
+ "AND sku.size = :size")
Related
I have a scenario in which I want to use the hibernate annotation #Filter (activated only if the condition is satisfied) but the condition needs to use alias (person as in the code snippet, because there is an ambiguous column in personId) from the original one which is written within Criteria. Note that the filter condition is written in sql. Besides the root.alias("person") don't work in this situation.
The model class:
#Entity
#Table(name = "PERSON")
#NoArgsConstructor
#Getter
#Setter
#Inheritance(strategy = InheritanceType.JOINED)
#FilterDef(name = "authorizePerson", parameters = {#ParamDef(name="userCode", type = "string")})
#Filter(name = "authorizePerson", condition =
" NOT EXISTS ("
+ " SELECT"
+ " multilevel1_.id_dossier,"
+ " multilevel1_.type_dossier"
+ " FROM"
+ " dossier_multiniv multilevel1_"
+ " WHERE"
+ " multilevel1_.id_dossier = TO_CHAR(**person**.id_per)"
+ " AND multilevel1_.type_dossier = 'PERSONNE'"
+ " )"
+ "OR EXISTS ("
+ " SELECT"
+ " multilevel2_.id_dossier,"
+ " multilevel2_.cd_util"
+ " FROM"
+ " v_droits_multiniv_allusers multilevel2_"
+ " WHERE"
+ " multilevel2_.cd_util = :userCode"
+ " AND multilevel2_.id_dossier = TO_CHAR(**person**.id_per)"
+ " AND multilevel2_.type_dossier = 'PERSONNE'"
+ " )", deduceAliasInjectionPoints = true)
public class PersonPO implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ID_PER")
private Long personId;
#Column(name = "AFFICH_PER")
private String archive;
#Column(name = "AUTH_ERROR")
private Long numberOfConnectionErrors;
// bi-directional many-to-one association to Categper
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ID_PER")
private PersonCategoryPO personCategory;
...
}
Then the service:
#Transactional
#Override
public Pageable<IPersonBO> findAllPersons(String stringFilter, Page page, Sort sort, String userCode) {
try {
Predicate filterPredicate = null;
CriteriaQuery<PersonPO> cq;
Root<PersonPO> root;
CriteriaBuilder cb = em.getCriteriaBuilder();
Predicate allPredicates = cb.equal(cb.literal(1), 1);
if (!stringFilter.isBlank()) {
SearchCondition<PersonPO> filter = new FiqlParser<PersonPO>(PersonPO.class).parse(stringFilter);
JPACriteriaQueryVisitor<PersonPO, PersonPO> jpa = new JPACriteriaQueryVisitor<PersonPO, PersonPO>(em,
PersonPO.class, PersonPO.class);
filter.accept(jpa);
cq = jpa.getQuery();
root = (Root<PersonPO>) cq.getRoots().iterator().next();
filterPredicate = jpa.getQuery().getRestriction();
allPredicates = filterPredicate;
} else {
cq = cb.createQuery(PersonPO.class);
root =cq.from(PersonPO.class);
}
cq.select(root.alias("person"));
Fetch<PersonPO, PersonCategoryPO> pc = root.fetch("personCategory");
Fetch<PersonCategoryPO, CategoryPO> category = pc.fetch("category");
CriteriaQuery<Long> cqCount = cb.createQuery(Long.class);
cqCount.select(cb.count(cqCount.from(PersonPO.class)));
if (multiLevelIsActif()) {
if (userCode != null) {
Filter filter = session.enableFilter("authorizePerson");
filter.setParameter("userCode", userCode);
}
}
cq.where(allPredicates);
cqCount.where(allPredicates);
// sort
JpaUtils.handleSort(sort, cq, cb, root);
// get results
TypedQuery<PersonPO> query = em.createQuery(cq);
if (page != null) {
query.setFirstResult(page.getFirstResult()).setMaxResults(page.getPageSize());
}
List<IPersonBO> items = query.getResultStream().map(c -> getPerson((PersonPO) c))
.collect(Collectors.toList());
// count results
Long totalSize = 0l;
totalSize = em.createQuery(cqCount).getSingleResult();
return new Pageable<IPersonBO>(items, totalSize, page);
} catch (Exception e) {
log.error(e.getMessage());
return null;
}
Why the sql-show still generates query and never consider the alias (person) like below ?
select
personpo0_.ID_PER as id_per1_102_,
...
from
RKHATERCHI2.PERSONNE personpo0_
...
where
1=1
order by
personpo0_.ID_PER desc
Is there a way how to enforce the alias in JPA/Criteria so that I can use it in the filter condition?
Your thoughts are appreciated.
Take a look into the documentation about how to specify table aliases in filter conditions: https://docs.jboss.org/hibernate/orm/5.6/userguide/html_single/Hibernate_User_Guide.html#pc-filter-sql-fragment-alias
I used postgresql 10 and spring boot
I try with success to load tree using loop in java.
in the loop I call each time the query
but it consumes cpu in application server and cpu in database server and takes time to load the tree which contain 5000 unit.
I want using only one query to load the tree without loop in java.
the result from java is ResponseEntity<List<UnitDTO>>
this is my code :
#GetMapping("/unitsBook")
#Timed
public ResponseEntity<List<UnitDTO>> getAllUnitsBook(Pageable pageable, #RequestParam(name="lang", required=false) String lang,
#RequestParam(name="emp", required=false) String empID) {
log.debug("REST request to get a page of Units");
Page<UnitDTO> page = unitService.findAllUnitBook(pageable, lang,empID);
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/unitsBook");
return ResponseEntity.ok().headers(headers).body(page.getContent());
}
the java code which contains the loop is :
public List<UnitDTO> getUnitBookList(Pageable pageable, String lang,String empID) {
List<UnitDTO> list=unitRepository.findUnitList(pageable, lang,empID);
List<UnitDTO> unitChildList=getChildrenUnitList(list,lang,pageable,empID);
return unitChildList;
}
private List<UnitDTO> getChildrenUnitList(
List<UnitDTO> unitList, String lang,Pageable pageable,String empID) {
for(UnitDTO UnitDTO : unitList) {
List<UnitDTO> childrenListEntity = unitRepository.findUnitByParentId(pageable, lang,UnitDTO.getValue(),empID);
UnitDTO.setChildren(getChildrenUnitList(childrenListEntity,lang,pageable,empID));
}
return unitList;
}
and the code which call query is :
public List<UnitDTO> findUnitList(Pageable pageable, String lang,String empID) {
String querystr = "SELECT ";
querystr += " unl.name AS text ,";
querystr += " un.id AS value ,";
querystr += " ,cast( 0 as varchar(10) ) as favoriteNbr,cast( null as varchar(10) ) as favoriteId ";
querystr += " FROM public.unit un ";
querystr += " LEFT OUTER JOIN public.unitlang unl ON unl.unit_id = un.id ";
querystr += " Where unl.lang = :lang parentid is null order by app_order asc";
log.debug("-- Query:" + querystr);
Query query = em.createNativeQuery(querystr, "UnitDTOMap");
query.setParameter("lang", lang);
List<UnitDTO> unitDTOs = query.getResultList();
if (pageable.isUnpaged()) {
return unitDTOs;
}
return unitDTOs;
}
#Override
public List<UnitDTO> findUnitByParentId(Pageable pageable, String lang, String idParent,String empID) {
log.debug("-- pageable:" + pageable.getPageNumber() + ", Size:" + pageable.getPageSize() + ", isUnpaged:" + pageable.isUnpaged() + ", lang:" + lang);
lang = lang.toUpperCase();
String querystr = "SELECT ";
querystr += " unl.name AS text ,";
querystr += " un.id AS value ,";
querystr += " (case when cast((select count(*) from employee where employee.unit_id = un.id) as varchar(10)) != '0' then cast(1 as Boolean) else cast(0 as BOOLEAN) end) as disabled";
querystr += " ,cast( 0 as varchar(10) ) as favoriteNbr,cast( null as varchar(10) ) as favoriteId ";
querystr += " FROM unit un ";
querystr += " LEFT OUTER JOIN unitlang unl ON unl.unit_id = un.id ";
querystr += " Where unl.lang = :lang and un.parentid = :idParent order by app_order asc ";
log.debug("-- Query:" + querystr);
Query query = em.createNativeQuery(querystr, "UnitBookDTOMap");
query.setParameter("lang", lang);
query.setParameter("idParent", idParent);
List<UnitDTO> unitDTOs = query.getResultList();
log.debug("-- unitDTOs Size:" + unitDTOs.size());
if (pageable.isUnpaged()) {
return unitDTOs;
}
return unitDTOs;
}
Updated :
I try to use the recursive query but the problem is that the tree does not display correctly.
all the unit are in same level.
I think the problem in this line WHERE id = :idParent I comment it because I didn't find how can I send it
public List<UnitDTO> getUnitBookList(Pageable pageable, String lang) {
List<UnitDTO> list=unitRepository.findUnitList(pageable, lang);
// List<UnitBookDTO> unitChildList=getChildrenUnitList(list,lang,pageable);
return list;
}
#Override
public List<UnitDTO> findUnitList(Pageable pageable, String lang) {
log.debug("-- pageable:" + pageable.getPageNumber() + ", Size:" + pageable.getPageSize() + ", isUnpaged:" + pageable.isUnpaged() + ", lang:" + lang);
lang = lang.toUpperCase();
String querystr = "WITH RECURSIVE un_id AS ( ";
querystr += " SELECT id";
querystr += " FROM unit ";
// querystr += " WHERE id = :idParent";
querystr += " UNION";
querystr += " SELECT unit.id";
querystr += " FROM unit JOIN un_id ON unit.parentid = un_id.id ) ";
querystr += " SELECT unl.name AS text, un.id AS value, (case when cast((select count(*) from employee where employee.unit_id = un.id) as varchar(10)) != '0' ";
querystr += " then cast(1 as Boolean) else cast(0 as BOOLEAN) end) as disabled , cast(0 as varchar(10)) as favoriteNbr,";
querystr += " cast(null as varchar(10)) as favoriteId FROM un_id JOIN unit un USING (id) LEFT OUTER JOIN unitlang unl ON unl.unit_id = un.id Where unl.lang = :lang order by app_order asc";
log.debug("-- Query:" + querystr);
Query query = em.createNativeQuery(querystr, "UnitDTOMap");
query.setParameter("lang", lang);
List<UnitDTO> unitDTOs = query.getResultList();
log.debug("-- unitDTOs Size:" + unitDTOs.size());
if (pageable.isUnpaged()) {
return unitDTOs;
}
return unitDTOs;
}
The usual way to fetch a tree in SQL is to use a recursive Common Table Expression (CTE):
WITH RECURSIVE un_id AS (
SELECT id
FROM unit
WHERE id = :idParent -- or parentid if you want to exclude the parent itself
UNION
SELECT unit.id
FROM unit
JOIN un_id
ON unit.parentid = un_id.id
)
SELECT unl.name AS text,
un.id AS value,
(case
when cast((select count(*) from employee where employee.unit_id = un.id) as varchar(10)) != '0'
then cast(1 as Boolean)
else cast(0 as BOOLEAN) end) as disabled
,
cast(0 as varchar(10)) as favoriteNbr,
cast(null as varchar(10)) as favoriteId
FROM un_id -- reference to the CTE
JOIN unit un
USING (id)
LEFT OUTER JOIN unitlang unl ON unl.unit_id = un.id
Where unl.lang = :lang
order by app_order asc
Recursively fetch all the IDs and then join the rest of the needed data.
In my code i have used List < Tuple > to capture the query results by joining various
tables and mapping to DTO object. This code works fine in the main. But
when i try to create a test case, i'm unable to cover the List < Tuple > code.
Please provide your inputs.
For Ex :
#SuppressWarnings("unchecked")
private List<FeedbackDTO> getList(String sortingProperty, String direction, UUID workflowId, UUID categoryId,
String type) {
StringBuilder query = new StringBuilder(
"select feedback.id, feedback.workflowId, user.userName, user.firstName, "
+ "user.lastName, feedback.submittedDate, country.countryName, "
+ "region.regionName, feedback.comments, feedback.ratings, feedback.acknowledged "
+ "from Feedback feedback, User user, Country country, Region region "
+ "where feedback.userId = user.id and user.countryId = country.id and user.regionId = region.id "
+ "and feedback.workflowId = " + "'" + workflowId + "'" + " and feedback.categoryId = " + "'"
+ categoryId + "'" + " and feedback.type = " + "'" + type + "'" + " order by ");
if (sortingProperty.equalsIgnoreCase("firstName")) {
query.append("user.firstName ");
}
query.append(direction);
Query queryList = entityManager.createNativeQuery(query.toString(), Tuple.class);
List<Tuple> tupleList = queryList.getResultList();
List<FeedbackDTO> feedbackList = new ArrayList<FeedbackDTO>();
for (Tuple tuple : tupleList) {
FeedbackDTO feedbackDTO = new FeedbackDTO();
feedbackDTO.setId(UUID.fromString((String) tuple.get("id")));
feedbackDTO.setUserName((String) tuple.get("userName"));
feedbackDTO.setFirstName((String) tuple.get("firstName"));
feedbackDTO.setLastName((String) tuple.get("lastName"));
feedbackDTO.setCountryName((String) tuple.get("countryName"));
feedbackDTO.setAcknowledged((Boolean) tuple.get("acknowledged"));
feedbackDTO.setRegionName((String) tuple.get("regionName"));
feedbackDTO.setComments((String) tuple.get("comments"));
feedbackDTO.setSubmittedDate((Date) tuple.get("submittedDate"));
feedbackDTO.setRatings((Double) tuple.get("ratings"));
feedbackList.add(feedbackDTO);
}
return feedbackList;
}
In My Test Case:
#Test
public void testGetFeedbackListNoFeedback() {
try {
Query queryList = mock(Query.class);
FeedbackTestDTO feedback = new FeedbackTestDTO();
feedback.setId(id);
feedback.setSolutionId(solutionId);
feedback.setComments("Please swich-on the power");
feedback.setType("Alternate Solution");
List<Object> tupleList = new ArrayList<>();
tupleList.add(feedback);
StringBuilder query = new StringBuilder(
"select * from feedback order by user.firstName ASC");
Sort sort = new Sort("firstName:ASC");
Pageable pageable = PageRequest.of(0, 20, sort);
when(entityManager.createNativeQuery(query.toString(), javax.persistence.Tuple.class)).thenReturn(queryList);
when(queryList.getResultList()).thenReturn(tupleList);
this.mockFeedbackListDTO = feedbackServiceImpl.getFeedbackList(workflowId, categoryId, "", "",
"2019-08-29T01:00:00Z", "2019-08-29T13:00:00Z", "5", pageable, true);
assertEquals(201, this.mockFeedbackListDTO.getCode());
} catch (BusinessException | ParseException be) {
assertEquals("No feedback from users", accessor.getMessage(be.getLocalizedMessage()));
}
}
List<Tuple> tupleList = new ArrayList<>();
NativeQueryTupleTransformer nativeQueryTupleTransformer = new NativeQueryTupleTransformer();
tupleList.add((Tuple)nativeQueryTupleTransformer.transformTuple(new BigDecimal[]{new BigDecimal(123),new BigDecimal(123),new BigDecimal(123)},new String[]{"0","1","2"} ));
tupleList.add((Tuple)nativeQueryTupleTransformer.transformTuple(new BigDecimal[]{new BigDecimal(123),new BigDecimal(123),new BigDecimal(123)},new String[]{"0","1","2"} ));
tupleList.add((Tuple)nativeQueryTupleTransformer.transformTuple(new BigDecimal[]{new BigDecimal(123),new BigDecimal(123),new BigDecimal(123)},new String[]{"0","1","2"} ));
Mockito.when(service.getRecordRangeForPagination(Mockito.anyString(),Mockit.anyLong(),Mockito.anyString())).thenReturn(tupleList);
It looks like your list is empty, therefore your for-loop is never examined.
Add an assertion that the expected size of the list should be of size 3:
List<Tuple> tupleResults = queryResults.getResultList();
// Check that the list is of size 3
Assert.assertTrue(tupleResults.size() == 3);
for(Tuple t : tupleResults) {
myDtoObject.setName(t.get("name")); //0
myDtoObject.setAge(t.get("age")); //1
myDtoObject.setSalary(t.get("salary"); //2
}
#Test
public void test() {
Query query = mock(Query.class);
List<Tuple> tupleList = new ArrayList<>();
when(query.getResultList().size() > 0).thenReturn(tupleList );
}
I am studying Hibernate and in a exercise I must do this query
"SELECT count(id) as numero_utenti, imc
FROM Utenti
WHERE azienda = '" + id + "' GROUP BY imc"
the problem is that, I don't know as view the result and to save the result in a string.
Thanks.
This is the function
public String getStat(int id) {
String stat = "";
int count = 0;
try {
Query query = session.createQuery("SELECT count(id) as numero_utenti, imc FROM Utenti WHERE azienda = '" + id + "' GROUP BY imc");
// as I extract the values?
tx.commit();
} catch (HibernateException he) {
throw he;
}
return stat;
}
If you are looking how to execute query using hibernate session.
query = session.createQuery("semect * from temp");
and query instance
Long.valueOf(query.fetchCountOfRows()).intValue();
It'll give you no. row count.
If they are not unique, get the list.
List<String> imcs= null;
int count = 0;
Query query = session.createQuery("SELECT imc FROM Utenti WHERE azienda = '" + id + "' GROUP BY imc");
imcs = query.list();
count = imcs.size();
I have three queries which I would like to consolidate into one query which can accept a variable length of WHERE arguments; I cannot remember for the life of me how to do this.
PreparedStatement queryOne = connection.prepareStatement
("SELECT columnOne, columnTwo, columnThree FROM tableOne WHERE columnOne = ?;" );
PreparedStatement queryTwo = connection.prepareStatement
("SELECT columnOne, columnTwo, columnThree FROM tableOne WHERE columnTwo = ?;" );
PreparedStatement queryThree = connection.prepareStatement
("SELECT columnOne, columnTwo, columnThree FROM tableOne WHERE columnOne = ? AND columnTwo = ?;" );
All three queries select the same columns from the same table, so their union can be easily done in one statement:
SELECT columnOne, columnTwo, columnThree
FROM tableOne
WHERE columnOne = ?
or columnTwo = ?
or (columnOne = ? AND columnTwo = ?)
Answered my own question, feel free to chime in on whether this is bad practice or not.
String columnOne = getValue();
String columnTwo = getValue();
String queryString = "SELECT columnOne, columnTwo, columnThree FROM tableOne"
if (columnOne != null && columnTwo != null)
queryString = queryString + "WHERE columnOne = ? AND columnTwo = ?"
else if (columnOne != null)
queryString = queryString + "WHERE columnOne = ?"
else if (columnTwo != null)
queryString = queryString + "WHERE columnTwo = ?"
PreparedStatement query = connection.prepareStatement(queryString);