Append Criteria query to previous query in Hibernate - java

I have a String array named andOrButtonFilter which stores and or filters selected by user.
Also two ArrayList named column and value storing column names and their values respectively.
I want the current query to append to the previous query and show the results
But my query is not being appended to the previous query, it is showing individual results.
For eg:
if name=xyz is first query and
age=26 is second query
It does not results with name=xyz and age=26 . It is only showing results for age=26 when executed for the second time.
Where am I going wrong?
This is the code I am using at the moment:
for (int i=0; i<andOrButtonFilter.length; i++)
{
if(andOrButtonFilter[i]=="and")
{
Conjunction conjunction =Restrictions.conjunction();
if ((column.get(i) != null) && (value.get(i)!=null))
{
conjunction.add(Restrictions.or(Restrictions.eq(column.get(i), value.get(i))));
criteriaQuery.add(conjunction);
}
}
else if(andOrButtonFilter[i]=="or")
{
Disjunction disjunction =Restrictions.disjunction();
if ((column.get(i) != null) && (value.get(i)!=null))
{
disjunction.add(Restrictions.or(Restrictions.eq(column.get(i), value.get(i))));
criteriaQuery.add(disjunction);
}
}
else
{
criteriaQuery.add(Restrictions.eq(column.get(i), value.get(i)));
}
}

I can find a few problems with you code.
1) You compare strings with == instead of equals. So your code always goes into the last section criteriaQuery.add(Restrictions.eq(column.get(i), value.get(i)));
2) In your conjunction/disjunction code you still use Restrictions.or which is kind of wrong. You don't even need Restrictions.or or Restrictions.and because Conjunction is adding the restrictions with AND anyway and Disjunction is adding with OR anyway.
3) On each iteration you add separate disjunction which is basically a single criterion and won't work as you expect.
I would try with something like:
Disjunction disjunction =Restrictions.disjunction();
Conjunction conjunction =Restrictions.conjunction();
for (int i=0; i<andOrButtonFilter.length; i++)
{
if("and".equals(andOrButtonFilter[i]))
{
if ((column.get(i) != null) && (value.get(i)!=null))
{
conjunction.add(Restrictions.eq(column.get(i), value.get(i)));
}
}
else if("or".equals(andOrButtonFilter[i]))
{
if ((column.get(i) != null) && (value.get(i)!=null))
{
disjunction.add(Restrictions.eq(column.get(i), value.get(i)));
}
}
else
{
criteriaQuery.add(Restrictions.eq(column.get(i), value.get(i)));
}
}
criteriaQuery.add(conjunction);
criteriaQuery.add(disjunction);
I am not saying that exact code will work because I haven't tested it ;) but you get the idea and you can debug from there.

Related

Optimize the several multiple OR conditions in IF statement

I am new to java and trying to learn a better way of coding.Please let me know if I can replace the multiple OR conditions in the below ELSE IF statement with any other way to execute based on the username passed in the calling method :
public void verifyPermissions(String user, String level2, String Folder) {
if (user.equalsIgnoreCase("ABC_Username")) {
verifyXYZPermission(Folder);
verifyNoPermissionToDelete();
}
else if (user.equalsIgnoreCase("DEF_Username") || user.equalsIgnoreCase("GHI_Username")
|| user.equalsIgnoreCase("JKL_Username") || user.equalsIgnoreCase("MNO_Username")
|| user.equalsIgnoreCase("PQR_Username") || user.equalsIgnoreCase("STU_Username")
|| user.equalsIgnoreCase("VWX_Username")) {
if (user.equalsIgnoreCase("GHI_Username")) {
verifyNoPermissionToCreate(user, Folder, level2);
verifyNoPermissionToUpdate(Folder);
} else {
verifyCreatePermission(level2);
verifyPermisssionToUpdate(Folder);
}
}
}
Here's one way: define a Set<String> with the possible username values before the if block, and check against it. Notice how all the strings were lower-cased to avoid trouble:
Set<String> userNames = new HashSet<>();
userNames.add("def_username");
userNames.add("ghi_username");
userNames.add("jkl_username");
userNames.add("mno_username");
userNames.add("pqr_username");
userNames.add("stu_username");
userNames.add("vwx_username");
// assuming `user` is non-null
user = user.trim().toLowerCase();
if (user.equals("abc_username")) {
verifyXYZPermission(Folder);
verifyNoPermissionToDelete();
} else if (userNames.contains(user)) {
if (user.equals("ghi_username")) {
verifyNoPermissionToCreate(user, Folder, level2);
verifyNoPermissionToUpdate(Folder);
} else {
verifyCreatePermission(level2);
verifyPermisssionToUpdate(Folder);
}
}
Use a switch-case statement.
In the case blocks for each user you can then execute the appropriate permissions.
https://www.w3schools.com/java/java_switch.asp
user_lc=user.toLowerCase();
switch (user_lc){
case "abc_user":
//execute code
break;
case "def_user":
//execute code
break;
}
It's highly opinionated I guess. Here are various approaches I can think of:
OR as you have done, or
regex to reduce lines of code, or
switch-case, or
Using a Collection such as List or Set.
It's all based on author's choice.

How do I build nested objects from sql query

I've got a query which returns data from several tables. In the application, these tables are classes one within another, for example a Client has several Orders, each Order has several OrderDetails, each OrderDetail has several Products, and so on... But I can't figure out a proper way to build the entire object in the app since the query returns one row for (let's just say) each product, so I have one client repeated over and over for every product it has bought.
So far I've tried this terribly inefficient code, and it works, problem is, it takes too much time for the app to process all of this information when it retrieves several clients.
boolean orderFound = false;
for (Order order1 : orders) {
if (order1 .getId() == order.getId()) {
orderFound = true;
if (od.getId() != 0) {
boolean odFound = false;
for (OrderDetail orderdetail : order1.getOrderDetail()) {
if (orderDetail.getId() == od.getId()) {
if (prod.getId() != 0) {
odFound = true;
boolean prodFound= false;
for (Product product: orderDetail.getProducts()) {
if (product.getId() == product.getId()) {
prodFound= true;
}
}
if (!prodFound) {
orderDetail.getProducts().add(dia);
}
}
if (!odFound) {
order1.getOrderDetail().add(od);
}
}
}
}
if (!orderFound) {
if (order.getId() != 0) {
orders.add(order);
This works, but there's gotta be a better way and I haven't found it. I've been told this can be solved using HashSets but I still don't know how to use them. Any help will be appreciated.
If you are open to using third party libraries, I think this is what you are looking for:
How to use hibernate to query for an object with a nested object that has a nested collection of objects

Reduce the complexity from code

I am using below code and used two continue statement depending on some logic but sonar list showing this issue Reduce the total number of break and continue statements in this loop to use at most one.
How to resolve this issue?
for (HashMap<String, String> objRequestIdVO : pObjTicketId) {
List<TicketDetailsDO> objTicketDetailslist = storeManagerDao.getTicketDetailsWithTicketId(objRequestIdVO.get("requestId"));
if (null == objTicketDetailslist || objTicketDetailslist.isEmpty()) {
continue;
}
Integer iDesiredDsicount = objTicketDetailslist.get(0).getDesiredDiscount();
String iSubDept = objTicketDetailslist.get(0).getSubdeptTicket().getSubDeptId();
List<MCouponDO> objMCounponList = storeManagerDao.getMcouponData(iDesiredDsicount, iSubDept);
if (null == objMCounponList || objMCounponList.isEmpty()) {
continue;
}
String strHeader = objMCounponList.get(0).getHeader();
objHeaderVO = new HeaderVO();
objHeaderVO.setHeader(strHeader);
objHeaderVO.setRequestId(objRequestIdVO.get("requestId"));
objHeaderVOList.add(objHeaderVO);
}
Change the null check continue, to not null check and proceed. The code will be executed only if the not null check passes, which is same as saying continue if null.
for (HashMap<String, String> objRequestIdVO : pObjTicketId) {
List<TicketDetailsDO> objTicketDetailslist = storeManagerDao.getTicketDetailsWithTicketId(objRequestIdVO.get("requestId"));
if (!(null == objTicketDetailslist || objTicketDetailslist.isEmpty())) {
Integer iDesiredDsicount = objTicketDetailslist.get(0).getDesiredDiscount();
String iSubDept = objTicketDetailslist.get(0).getSubdeptTicket().getSubDeptId();
List<MCouponDO> objMCounponList = storeManagerDao.getMcouponData(iDesiredDsicount, iSubDept);
if (!(null == objMCounponList || objMCounponList.isEmpty()) {
String strHeader = objMCounponList.get(0).getHeader();
objHeaderVO = new HeaderVO();
objHeaderVO.setHeader(strHeader);
objHeaderVO.setRequestId(objRequestIdVO.get("requestId"));
objHeaderVOList.add(objHeaderVO);
}
}
}
You could use streams replacing the continues with filters.
pObjTicketId.stream()
.map(m-> m.get("requestId"))
.map(reqId ->
Optional.ofNullable(storeManagerDao.getTicketDetailsWithTicketId(reqId))
.filter(l->!l.isEmpty())
.map(l->l.get(0))
.map(ticketDetails->
storeManagerDao.getMcouponData(ticketDetails.getDesiredDiscount(),
ticketDetails.getSubdeptTicket().getSubDeptId())
)
.filter(Objects::nonNull)
.filter(l->!l.isEmpty())
.map(l->l.get(0))
.map(couponDo-> {
HeaderVO headerVO = new HeaderVO();
headerVO.setHeader(couponDo.getHeader());
headerVO.setRequestId(oreqId);
return headerVO;
})
)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
You have a bigger problem than fixing Sonar warning if calls - storeManagerDao.getTicketDetailsWithTicketId(objRequestIdVO.get("requestId")) & storeManagerDao.getMcouponData(iDesiredDsicount, iSubDept) are about making DB calls.This is a big performance point and one should - Never ever make DB calls from within a loop, this is far more dangerous than multiple continue & break statements
So I would first restructure your DAO call - storeManagerDao.getTicketDetailsWithTicketId to run IN sql query for a bunch of objRequestIdVO.get("requestId") in one go , outside your main loop & produce a Map<String,List<TicketDetailsDO>> ...that will automatically get rid of your first if .
Next you repeat same process for constructing a Map<String,List<MCouponDO> objMCounponList> by iterating previous map Map<String,List<TicketDetailsDO>> where key of this map is something like - iDesiredDsicount|iSubDept .
This way you will have two disconnected loops and only two DB calls & your Sonar warning gets automatically solved on the way.

Problems with Hibernate Criteria API (Disjunction and Conjunction)

I have a problem with using Conjunctions and Disjunctions. My program receives an arbitrary number of filter elements (each representing a Criterion) from the ui and is intended to chain together them as an AND or OR.
So for example I can have 3 elements like this (I represent a Criterion with a letter):
a OR b AND c
My code looks like this:
// ...
Criteria rootCriteria = createCriteria(entityClass);
Conjunction conjunction = Restrictions.conjunction();
Disjunction disjunction = Restrictions.disjunction();
boolean isFirst = true;
for (InternalFilterElement element : elements) {
if (isFirst) {
isFirst = false;
rootCriteria.add(createCriterion(element.getFilterRelation(), element.getValue()));
} else if (InternalFilterOperand.AND.equals(element.getInternalFilterOperand())) {
addCriterionToJunction(conjunction, element);
} else {
addCriterionToJunction(disjunction, element);
}
}
rootCriteria.add(disjunction);
rootCriteria.add(conjunction);
// ...
My problem is that I always get a AND b AND c and some unnecessary parentheses.
What I really wish to know is that I am using the wrong tool for this task or not? How can I mix AND and OR operators?
edit
InternalFilterOperand is basically an enum containing OR and AND
addCriterionToJunction just adds a Criterion to the Junction based on the relation (<, >, ...) and the value. It does not have any side effects.
By using the following code, you mix AND and OR operators in Hibernate:
Criteria rootCriteria = createCriteria(entityClass);
rootCriteria.add(Restrictions.or(
Restrictions.eq("a","a"),
Restrictions.and(
Restrictions.eq("b","b"),
Restrictions.eq("c","c")
)
));
This example results in the following output: a=a OR b=b AND c=c without the parenthesis you would get with conjunction and disjunction.
You're making it harder than necessary. Why not just use the following:
Junction junction =
InternalFilterOperand.AND.equals(element.getInternalFilterOperand()) ?
Restrictions.conjunction() :
Restrictions.disjunction();
for (InternalFilterElement element : elements) {
addCriterionToJunction(junction, element);
}
rootCriteria.add(junction);
I am close to believe that InternalFilterOperand is not set correctly in your elements as everything else looks right.
Please print/debug the element.getInternalFilterOperand() values in your loop as first statement to verify and correct.
EDIT: Try adding conjunction/disjunction directly in the rootCriteria
for (InternalFilterElement element : elements) {
if (isFirst) {
isFirst = false;
rootCriteria.add(
createCriterion(element.getFilterRelation(), element.getValue()));
}else if (InternalFilterOperand.AND.equals(element.getInternalFilterOperand())){
//add debugg/sys out: adding conjunction
System.out.println("adding conjunction");
rootCriteria.add(Restrictions.conjunction().add(element));
} else {
//add debugg/sys out: adding disjunction
System.out.println("adding disjunction");
rootCriteria.add(Restrictions.disjunction().add(element));
}
}

Issue in loop getting the value

I am having an issue in getting the data in the below loop ,even though the size is not zero i am getting null in the sysout 'data is'.What is wrong there ?
List<Long> dd = domainItemMapper.getIsSearchable(34372);
System.out.println("the test is-" + dd.size());
for (int i = 0; i < dd.size(); i++) {
Long isSearch = dd.get(i);
System.out.println("data is"+dd.get(i));
if (isSearch.equals(0)) {
isSearchValue = false;
} else
isSearchValue = true;
}
The call to database is a mybatis call as below
interface
List<Long> getIsSearchable(#Param("parentFieldId") long parentFieldId);
impl
<mapper namespace="com.ge.dbt.common.persistence.IFormValidatorMapper">
<select id="getIsSearchable" statementType="CALLABLE"
resultType="Long">
select is_searchable from t_field where parent_field_id=#{parentFieldId}
</select>
</mapper>
I guess your whole code can be converted in to two lines.
if(dd!= null && !dd.isEmpty())
return dd.contains(0);//Contains Guard you in such cases because equals check
//happen on passed element ie *0*
Default value of Long in java is null. So you will need additional check for null in your case.
Enclose your isSearch.equals check in a null check
if(isSearch != null)
{
if (isSearch.equals(0))
{
isSearchValue = false;
}
else
{
isSearchValue = true;
}
}
However it'll be better to modify code for domainItemMapper.getIsSearchable(34372); method so that it doesn't fill the list with null at all.
Seems to be your list contains null literals. And List Supports null as a value.
based on your this comment
The data has null,0 and 1 data.I want to return data only for 0 and 1.
You need to fix your query like this
select is_searchable from t_field where parent_field_id=#{parentFieldId} and is_searchable is not NULL;

Categories

Resources