Ormlite Query BuilderCondition - java

i have a user form, the user specify the research criteria and i must apply them to get the right data from the database using ormlite :
boolean set = false;
QueryBuilder<Client, Integer> builder = clientsDao.queryBuilder();
Where<Client, Integer> builderWhere = builder.where();
if (!tfSearchName.getText().equals("")) {
builderWhere.like("name", tfSearchName.getText().trim());
builderWhere.and();
set = true;
}
if (!tfSearchBalanceMin.getText().equals("")) {
builderWhere.gt("balance", tfSearchBalanceMin);
builderWhere.and();
set = true;
}
if (!tfSearchBalanceMax.getText().equals("")) {
builderWhere.lt("balance", tfSearchBalanceMax);
set = true;
}
clientTable.setItems(FXCollections.observableArrayList(
set ? clientsDao.query(builderWhere.prepare())
: clientsDao.queryForAll()));
the problem with the query builder is there is always an and Clause in the end so that always throw an expection.
i want to know a good way to generate my sql statement using condition like i do in my code.
PS : sorry for bad english

You could try to use public Where<T, ID> and(int numClauses)
For example:
int andClauses= 0; // number of clauses that should be connected with "and" operation
QueryBuilder<Client, Integer> builder = clientsDao.queryBuilder();
Where<Client, Integer> builderWhere = builder.where();
if (!TextUtils.isEmpty(tfSearchName.getText())) {
builderWhere.like("name", tfSearchName.getText().trim());
andClauses++;
}
if (!TextUtils.isEmpty(tfSearchBalanceMin.getText())) {
builderWhere.gt("balance", tfSearchBalanceMin);
andClauses++;
}
if (!TextUtils.isEmpty(tfSearchBalanceMax.getText())) {
builderWhere.lt("balance", tfSearchBalanceMax);
andClauses++;
}
clientTable.setItems(FXCollections.observableArrayList(
andClauses > 0 ? clientsDao.query(builderWhere.and(andClauses).prepare())
: clientsDao.queryForAll()));

Related

Room database RawQuery() is not work on "IN" and "NOT IN" clause

I have my one table like UserTable.
#Entity
public class UserTable{
#PrimaryKey(autoGenerate = true)
private int userId;
private String userName;
private String userEmailId;
// Below code is getter and setter of this class.
}
#Dao
public interface UserDao {
#Query("SELECT * FROM userTable")
public List<UserTable> loadAllUsers();
#Insert
public long insertUserTable(UserTable userTable);
#Insert
public long[] insertUserTables(UserTable... userTables);
#Update
public int updateUserTable(UserTable userTable);
#Delete
public int deleteUserTable(UserTable userTable);
#RawQuery
public abstract List<UserTable> loadAllUserListByGivenIds
(SupportSQLiteQuery query);
public default List<UserTable> loadAllUserListByIds(long[] userIds) {
List<UserTable> list;
ArrayList<Object> argsList = new ArrayList<>();
String selectQuery = "SELECT * FROM UserTable WHERE userId IN (?);";
argsList.add(userIds);
SimpleSQLiteQuery simpleSQLiteQuery = new SimpleSQLiteQuery(selectQuery, argsList.toArray());
list = loadAllUserListByGivenIds(simpleSQLiteQuery);
return list;
}
}
// Now in My MainActivity.class file, I have use following code:
List<UserTable> userList= databaseClient
.getAppDatabase()
.userDao()
.loadAllUserListByIds(new long[]{1L,2L});
My query is running in normal database, but when I was pass array of user ids then, in #RawQuery() method of dao class is not supported for "IN" clause used in where condition "WHERE userId IN (?)".
How, I will use "IN" clause in #RawQuery() of room database.
Much easier to use an #Query it's as simple as:-
#Query("SELECT * FROM UserTable WHERE userId IN (:idList)")
public List<UserTable> getWhatever(long[] idList);
You'd then use getWhatever(new long[]{1L,2L})
If you need it an #rawQuery though you could do it like (used previous answer code for my convenience) :-
private List<TableXEntity> loadAllUserListByIds(int order,long[] idList) {
StringBuilder idListAsCSV = new StringBuilder(); //<<<<<<<<<<
boolean afterFirst = false; //<<<<<<<<<<
//<<<<<<<<<< all of the loop to create the CSV
for (Long l: idList) {
if (afterFirst) {
idListAsCSV.append(",");
}
afterFirst = true;
idListAsCSV.append(String.valueOf(l));
}
StringBuilder sb = new StringBuilder("SELECT * FROM ").append(DBHelper.TableX.NAME);
sb.append(" WHERE " + DBHelper.TableX.COLUMN_ID + " IN(").append(idListAsCSV).append(") "); //<<<<<<<<<<
switch (order) {
case DBHelper.TableX.FIRSTNAME_DESCENDING:
sb.append(DBHelper.TableX.ORDER_BY_FIRSTNAME_DESC);
break;
case DBHelper.TableX.FIRSTNAME_ASCENDING:
sb.append(DBHelper.TableX.ORDER_BY_FIRSTNAME_ASC);
break;
case DBHelper.TableX.LASTNAME_DESCENDING:
sb.append(DBHelper.TableX.ORDER_BY_LASTNAME_DESC);
break;
case DBHelper.TableX.LASTNAME_ASCENDING:
sb.append(DBHelper.TableX.ORDER_BY_LASTNAME_ASC);
break;
default:
break;
}
sb.append(";");
return roomDao.rawq(new SimpleSQLiteQuery(sb.toString(),null));
}
i.e. provide a CSV (although I vaguely recall being able to pass an array)
To use bind arguments (the recommended way as binding arguments protects against SQL injection) then you need a ? for each value and a corresponding array of objects.
So for 3 id's you need IN(?,?,?) and the actual values, the bind arguments, in an Object[]. The following is an example that does this noting that it shows 2 ways of building the Object[] (the bind arguments/values):-
private List<TableXEntity> loadByidList(long[] idlist) {
List<Object> bindargs = new ArrayList<>(); // way 1
Object[] args4Bind = new Object[idlist.length]; // way 2
StringBuilder placeholders = new StringBuilder(); // for the ? placeholders
/* Build the sql before the place holders */
StringBuilder sql = new StringBuilder("SELECT * FROM ")
.append(DBHelper.TableX.NAME)
.append(" WHERE ")
.append(DBHelper.TableX.COLUMN_ID)
.append(" IN (");
boolean afterfirst = false;
int i = 0; /* using for each so have index counter (as opposed to for(int i=0 ....) */
for (long l: idlist) {
bindargs.add(l); // for way 1
args4Bind[i++] = String.valueOf(l); // for way 2
if (afterfirst) {
placeholders.append(",");
}
afterfirst = true;
placeholders.append("?");
}
/* finalise the SQL */
sql.append(placeholders.toString())
.append(");");
//return roomDao.rawq(new SimpleSQLiteQuery(sql.toString(),bindargs.toArray())); // way 1
return roomDao.rawq(new SimpleSQLiteQuery(sql.toString(),args4Bind)); // way 2
}
Please try this, here it has working!
Try this simple trick to pass the arguments for IN operator-
List<Object> argList = new ArrayList<>();
argList.add("3");
argList.add("6");
Then prepare your raw query string:
Note- Match your argument list size with '?' size
String selectQuery = "SELECT * FROM task WHERE id IN (?,?)";
After this pass the raw query string to SimpleSQLiteQuery-
SimpleSQLiteQuery rawQuery = new SimpleSQLiteQuery(selectQuery, args.toArray());
Then fetch the List using DAO:
List<UserTable> taskList1=DatabaseClient
.getInstance(getApplicationContext())
.getAppDatabase()
.userTableDAO()
.getAllList(query);
We can do it in kotlin in the more simpler way.
Let's create two helper methos
object Helper {
fun sqlIn(list: List<Any>, bindArgs: MutableList<Any>): String {
bindArgs.apply { this.addAll(list) }
return "IN (${list.joinToString(",") { "?" }})"
}
fun sqlNotIn(list: List<Any>, bindArgs: MutableList<Any>): String = "NOT ${sqlIn(list, bindArgs)}"
}
Then you can use it in anywhere else
val ids = listOf(1, 2, 3)
val ownerId = 10
val bindArgs = mutableListOf<Any>()
val query = "SELECT * FROM posts WHERE id ${Helper.sqlIn(ids, bindArgs)} AND owner_id = ?"
bindArgs.add(ownerId)
dao.query(
SimpleSQLiteQuery(query, bindArgs.toTypedArray())
)

Can we Replace a portion of String in Java which has symbol in the start and end to Identify?

I have a String SELECT *FROM USERS WHERE ID = '#userid#' AND ROLE = '#role#'
Now i have replace any string between #...# , with a actual value .
Expected output SELECT *FROM USERS WHERE ID = '4' AND ROLE = 'Admin'
This replace will happen from a method , i have written this logic
public String replaceQueryKeyWithValueFromKeyValues(String query, int reportId) {
try {
REPMReportDao repmReportDao = new REPMReportDao();
int Start = 0;
int end;
if (query.contains("#")) {
boolean specialSymbolFound = false;
for (int i = 0; i < query.length(); i++) {
if (query.charAt(i) == '#') {
if (!specialSymbolFound) {
Start = i + 1;
specialSymbolFound = true;
} else {
specialSymbolFound = false;
end = i;
query = query.replace(query.substring(Start - 1, end + 1), repmReportDao.getReportManagerKeyValue(query.substring(Start - 1, end + 1).replaceAll("#", ""), reportId));
}
}
}
return query;
} else {
return query;
}
} catch (Exception e) {
logger.log(Priority.ERROR, e.getMessage());
return e.getMessage();
}
}
It works fine , but in the case if a single '#' symbol exist instead of start and end it will fail.
Like :
SELECT *FROM USERS WHERE emailid = 'xyz#gmail.com' AND ROLE = '#role#'
Here it should replace the only role '#role#' and should left email as it is.
Expected Output => SELECT *FROM USERS WHERE emailid = 'xyz#gmail.com' AND ROLE = 'Admin'
Complete example with mocked data returned by getReportManagerKeyValue:
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class StackOverflow54842971 {
private static Map<String, String> map;
public static void main(String[] args) {
// preparing test data
map = new HashMap<>();
map.put("role", "Admin");
map.put("userid", "666");
// original query string
String query = "SELECT * FROM USERS WHERE ID = '#userid#' AND emailid = 'xyz#gmail.com' AND ROLE = '#role#' ";
// regular expression to match everything between '# and #' with capture group
// omitting single quotes
Pattern p = Pattern.compile("'(#[^#]*#)'");
Matcher m = p.matcher(query);
while (m.find()) {
// every match will be replaced with value from getReportManagerKeyValue
query = query.replace(m.group(1), getReportManagerKeyValue(m.group(1).replaceAll("#", "")));
}
System.out.println(query);
}
// you won't need this function
private static String getReportManagerKeyValue(String key) {
System.out.println("getting key " + key);
if (!map.containsKey(key)) {
return "'null'";
}
return map.get(key);
}
}
It's considered very bad practice to use string substitution to generate database queries, because you leave your code open to SQL Injection attacks. I can't tell from the small code sample you've provided, but the vast majority of large-scale Java projects use the Spring Framework, which allows you to use either JdbcTemplate or (my preference) NamedParameterJdbcTemplate. Both will allow you to substitute variables in a safe manner.

Spring boot Is it possible to group predicates or use 'in' conditionally

I'm having issues properly grouping my query using CriteriaBuilder and Predicates.
I want to create a query that can generate something like:
SELECT * from tableName where columnA = '1234' and (columnB Like '%33%' or columnB Like '%44%')
But what I'm getting (Obviously expected looking at the code) is:
SELECT * from tableName where columnA = '1234' and columnB Like '%33%' or columnB Like '%44%'
Which does not produce the same result as the first query.
Been trying to work around it, but this is my first time working with criteriaBuilder and predicates.
Here's the code:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Foo> criteriaQuery = builder.createQuery(Foo.class);
Root r = criteriaQuery.from(Foo.class);
Predicate predicate = builder.conjunction();
for(Map.Entry<String, String> entry : searchParams.entrySet()){
if((entry.getKey().equalsIgnoreCase("columnK") || entry.getKey().equalsIgnoreCase("columnY") ||
entry.getKey().equalsIgnoreCase("columnZ") || entry.getKey().equalsIgnoreCase("columnJ")) && !Strings.isNullOrEmpty(entry.getValue())){
predicate = builder.and(predicate,
builder.like(r.get(entry.getKey()),
String.format("%%%s%%", entry.getValue().toString())));
}
else if(entry.getKey().equalsIgnoreCase("theDate") && !Strings.isNullOrEmpty(entry.getValue())){
predicate = builder.and(predicate, builder.equal(r.get(entry.getKey()), entry.getValue()));
}
}
//here's where the problem is ... I realize I can use IN, but I also didn't get that to work
boolean isFirstDone = false;
for(String oneId: idStringList){
if(!isFirstDone) {
predicate = builder.and(predicate, builder.equal(r.get("acceptorId"), oneId));
isFirstDone = true;
}
else{
predicate = builder.or(predicate, builder.equal(r.get("acceptorId"), oneId));
}
}
criteriaQuery.where(predicate);
Thank you.
Okay, so I just cracked this after carefully reading this answer https://stackoverflow.com/a/9323183/5038073 The solution is not exactly what I needed but it helped... a lot
I created a path and combined it with my predicate.
Here's what changed:
This:
boolean isFirstDone = false;
for(String oneId: idStringList){
if(!isFirstDone) {
predicate = builder.and(predicate, builder.equal(r.get("acceptorId"), oneId));
isFirstDone = true;
}
else{
predicate = builder.or(predicate, builder.equal(r.get("acceptorId"), oneId));
}
}
became:
Path<Object> path = r.get("acceptorId");
CriteriaBuilder.In<Object> in = builder.in(path);
for (String oneId: idStringList) {
in.value(oneId);
}
predicate = builder.and(predicate, in);
Pretty simple for all the trouble it took me to solve.
Hope this helps someone else too!

how to disable page query in Spring-data-elasticsearch

I use spring-data-elasticsearch framework to get query result from elasticsearch server, the java code like this:
public void testQuery() {
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withFields("createDate","updateDate").withQuery(matchAllQuery()).withPageable(new PageRequest(0,Integer.MAX_VALUE)).build();
List<Entity> list = template.queryForList(searchQuery, Entity.class);
for (Entity e : list) {
System.out.println(e.getCreateDate());
System.out.println(e.getUpdateDate());
}
}
I get the raw query log in server, like this:
{"from":0,"size":10,"query":{"match_all":{}},"fields":["createDate","updateDate"]}
As per the query log, spring-data-elasticsearch will add size limit to the query. "from":0, "size":10, How can I avoid it to add the size limit?
You don't want to do this, you could use the findAll functionality on a repository that returns an Iterable. I think the best way to obtain all items is to use the scan/scroll functionality. Maybe the following code block can put you in the right direction:
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchAllQuery())
.withIndices("customer")
.withTypes("customermodel")
.withSearchType(SearchType.SCAN)
.withPageable(new PageRequest(0, NUM_ITEMS_PER_SCROLL))
.build();
String scrollId = elasticsearchTemplate.scan(searchQuery, SCROLL_TIME_IN_MILLIS, false);
boolean hasRecords = true;
while (hasRecords) {
Page<CustomerModel> page = elasticsearchTemplate.scroll(scrollId, SCROLL_TIME_IN_MILLIS, CustomerModel.class);
if (page != null) {
// DO something with the records
hasRecords = (page.getContent().size() == NUM_ITEMS_PER_SCROLL);
} else {
hasRecords = false;
}
}

NSNotFound equivalent in Java

I need to know if there is a way to say that int type is not found in Java Android.
I'm writing an android application,which is actually written first for Iphone, and have a little issue. At some point I have to check if the int type which returns a method is not found and if it's true do some calculations. The problem is that when I did that in Java as if(Id==0) it's throwing me an exception even if the Id is 0.
this is my method :
private static int localUserIdByServerUserId(int serverUserId, String serverName){
dbHelper = new DataBaseHelper(context, "stampii_sys_tpl.sqlite", null, 1);
dbHelper.getDatabase();
String query = "SELECT id FROM users WHERE objectId = "+serverUserId+" AND serverName = '"+serverName+"' LIMIT 1";
ArrayList<String> result = new ArrayList<String>();
cursor = dbHelper.executeSQLQuery(query);
cursor.moveToFirst();
while(!cursor.isAfterLast()) {
result.add(cursor.getString(cursor.getColumnIndex("id")));
cursor.moveToNext();
}
Log.i("result ","Result : "+result.toString());
Log.i("CURSOR ","Cursor Position : "+cursor.getPosition());
int uuid = Integer.parseInt(result.get(cursor.getColumnIndex("objectId")+1));
Log.w("localUSerByIdServerUserId","LocalUserByIdServerUserId result : "+uuid);
cursor.close();
return uuid;
and here is how I'm using it :
int uuId = rpc.lUserIdByServerUserId(userId,newServerName);
Log.w("uuId","uuId : "+uuId);
if(uuId==0){
// do some calculations
}
Any suggestions ?
lUserIdByServerUserId() could throw an exception when the user is not found.
e.g.
try {
int uuId = rpc.lUserIdByServerUserId(userId,newServerName);
Log.w("uuId","uuId : "+uuId);
}
catch (NotFoundException nfe) {
// do some calculations
}
You will need to modify lUserIdByServerUserId() to throw the exception. You may also need to define your own NotFoundException class if a suitable exception doesn't already exist in the Java libraries.
EDIT:
Alternatively, following on from #mthpvg's answer, you could change lUserIdByServerUserId() to return an Integer type, which can be set to null if not found and tested.
e.g.
Integer uuId = rpc.lUserIdByServerUserId(userId,newServerName);
if (uuId == null) {
// Do some calculations
}

Categories

Resources