According to this post :Multiple, combined OR conditions in ORMLite
I want to make queries that can depend on ArrayList of condition and Strings in function
List<String> cat = new ArrayList<String>();
List<Person> line = new ArrayList<>();
Dao<Person, Integer> personDAO = getHelper().getPersonDAO();
cat.add("category1");
cat.add("category2");
QueryBuilder<Person, Integer> queryBuilder = personDAO.queryBuilder();
Where<Person, Integer> where = queryBuilder.where();
if(filterOn)
for (int i = 0; i < cat.size(); ++i)
where.eq("category", cat.get(i)).or().eq("name", cat.get(i));
where.or(cat.size());
if(searchBar.size()!=0){
for (int i = 0; i < cat.size(); ++i)
where.eq("category", cat.get(i)).or().eq("name", cat.get(i));
where.like("category", constrainName).or().like("name", constrainName);
where.or(cat.size()+1);
}
line = personDAO.queryBuilder().query();
But Ive got throw out of application without any exception whenever the first iteration of loop is finished
UPDATE: I solve my problem. solution was:
for (int i = 0; i < cat.size(); ++i)
where.eq("category",cat.get(i)).or().eq("name",cat.get(i));
where.or(cat.size());
if(data){
where.like("category", t).or().like("name", t);
l = personDAO.query(where.and(2).prepare());
} else
l = personDAO.query(where.or(1).prepare());
But I've got throw out of application without any exception whenever the first iteration of loop is finished
Ok, first off, unless the JVM quit on you there was an exception, just that it was not properly caught or logged somehow. If you enable logging I suspect the exception would have explained the problem.
There are number of problems with your code. I'm not sure which one (or something else) is causing the exception to be thrown. The first problem is:
if (filterOn) {
for (String entry : cat) {
where.eq("category", entry);
where.eq("name", entry);
}
where.or(cat.size() * 2);
}
The fix here is to only add the ORs if the filterOn is set. Otherwise you would have generated an invalid query. I recommend always using {} so you can see these sorts of issues. I do one call to where.or(...) with the size * 2 for the category and name.
if(searchBar.size()!=0){
So this seems to be adding the category and name equals comparisons in as well. If filterOn and !searchBar.isEmpty() can be true at the same time then you are going to get duplicate WHERE entries which is inefficient. However, it might also generate an incomplete query because if you add a number of OR entries that match the category/name and then do it again, you need one more OR to link the two sets. For example:
if (filterOn) {
where.eq("category", entry);
where.eq("name", entry);
where.or(2);
}
if (!searchBar.isEmtpy()) {
where.eq("category", entry);
where.eq("name", entry);
where.like("category", entry);
where.like("name", entry);
where.or(4);
}
// MISSING LAST OR HERE if both conditions are true
This code would generate an invalid query exception because you are missing the last OR which ties the two sets of comparisons together.
What I would recommend is to count the number of ORs added to the query:
int orCount = 0;
if (filterOn) {
// loop here
for loop {
where.eq("category", entry);
where.eq("name", entry);
orCount += 2;
}
}
if (!searchBar.isEmtpy()) {
for loop {
where.eq("category", entry);
where.eq("name", entry);
orCount += 2;
}
where.like("category", entry);
where.like("name", entry);
orCount += 2;
}
where.or(orCount);
This will put the appropriate number of ORs into your query at the end.
Couple other comments:
cat should be cats at least to show that it is storing multiple. Same for line.
Consider using the for (String cat : cats) type of for instead of using for (int i = 0; ...) { ... cats.get(i) ... }. The first type is less prone to errors with the counter.
Related
The error:
java.lang.ArrayIndexOutOfBoundsException: length=2; index=2
at WeekView.getMoreEvents(WeekView.java:614)
In a class that extends View, I get a list of the id in this way:
public void setElencoIdOperatori(int[] id_nome_op){
this.id_nome_op = id_nome_op;
}
Then, with this method, I must compare id_nome_op with eventRect.event.getIdOperatore(). When are the same, I want to add the event to the array eventRects. Thanks for your help
private void getMoreEvents(Calendar day){
// Get more events if the month is changed.
if(mEventRects ==null)
mEventRects =newArrayList<EventRect>();
if(mMonthChangeListener ==null&&!isInEditMode())
thrownewIllegalStateException("You must provide a MonthChangeListener");
// If a refresh was requested then reset some variables.
if(mRefreshEvents){
mEventRects.clear();
mFetchedMonths =newint[3];
}
...
// Get events of this month.
if(mFetchedMonths[1]<1||mFetchedMonths[1]!= day.get(Calendar.MONTH)+1||mRefreshEvents){
if(!containsValue(lastFetchedMonth,day.get(Calendar.MONTH)+1)&&!isInEditMode()){
List<WeekViewEvent> events =mMonthChangeListener.onMonthChange(day.get(Calendar.YEAR),day.get(Calendar.MONTH)+1);
sortEvents(events);
for(WeekViewEventevent: events){
cacheEvent(event);
}
}
mFetchedMonths[1]= day.get(Calendar.MONTH)+1;
}
...
// Prepare to calculate positions of each events.
ArrayList<EventRect> tempEvents =newArrayList<EventRect>(mEventRects);
mEventRects =newArrayList<EventRect>();
for(intj =1;j <=id_nome_op.length;){
ArrayList<EventRect> eventRects =newArrayList<EventRect>();
for(EventRect eventRect : tempEvents){
if(eventRect.event.getIdOperatore() == id_nome_op[j])
eventRects.add(eventRect);
}
computePositionOfEvents(eventRects);
j++;
}
}
It's a bit hard understanding your code, but I think you might have a problem here:
for(int j =1;j <=id_nome_op.length;) {
ArrayList<EventRect> eventRects =newArrayList<EventRect>();
for(EventRect eventRect : tempEvents){
if(eventRect.event.getIdOperatore() == id_nome_op[j])
eventRects.add(eventRect);
}
computePositionOfEvents(eventRects);
j++;
}
When you access id_nome_op[j].
Try changing the loop to:
j < id_nome_op.length
As #Mike M pointed out, you also need initalizing your outer loop to 0, as you want to get all the items in your array:
for(int j = 0; j < id_nome_op.length;)
Suppose I have LinkedhashMap<String, List> myLHM = new LinkedHashMap<>()
Values of myLHM :
<Roy,[1,2,3]>
<Roy,[14,15,16]>
<Neha,[1,5,6]>
<Neha,[11,12,13]>
<Jane,[11,8,9]>
In above eg., Roy and Neha is repetitive/duplicate.
Is it possible to hold duplicate keys in myLHM ? Because I'm not able to store duplicate keys
No? Then what is the alternative to LinkedHashMap to hold duplicate keys?
TIA!
Edit: Those two Roy and Neha are each the same person
I don't know of any map in the standard java library that can hold duplicate keys, but Guava is an excellent extension to the normal java Collections (and more) done by Google. There you have Multimap which can hold several values for the same key (I guess this is what you want in the end). The main benefit I find in using such a library/implementation is that it will take care of everything for you associated with the storage of the values and you don't need to bother about implementing it yourself.
PS: Guava is not just about Collections, which I think it's another Pro why you should check it out.
Add a List of items by key. Whenever you insert, if key was found, just add to the collection. When not found, add a new colelction with current item.
I solved this by myself.
What I did is used :
LinkedHashMap<String, ArrayList<ArrayList>> myLHM = new LinkedHashMap<>() ;
Inserted into it as:
ArrayList<ArrayList> multiDimArray = new ArrayList<>();
ArrayList list = new ArrayList();
list.add("abc");//some string 1
list.add("lmn");//some string 2
list.add("xyz");//some string 3
multiDimArray.add(list);
myLHM.put("abc"/*use your variable OR pass value like myList.get(position)*/,multiDimArray);
Fetched / Retrieved values as:
List tempNames=new ArrayList();
Iterator myVeryOwnIterator = myLHM.keySet().iterator();
while(myVeryOwnIterator.hasNext()) {
tempNames.add(myVeryOwnIterator.next());
}
ArrayList<ArrayList> tempArrayList = new ArrayList();
for (int i=0;i<tempNames.size();i++){
tempArrayList.addAll(myLHM.get(tempNames.get(i)));
}
String item = null; int year = 0; int amount = 0;
for (int i=0;i<tempArrayList.size();i++) {
for (int j=0;j<tempArrayList.get(i).size();j++){
if(j==0){
item = (String) tempArrayList.get(i).get(j);
item = item.replaceAll("\\s", "_");
} else if (j==1){
year = Integer.valueOf(tempArrayList.get(i).get(j).toString());
} else if (j==2){
amount = Integer.valueOf(tempArrayList.get(i).get(j).toString());
} else {
Log.e("Problem","for loop error");
}
}
db.execSQL("INSERT INTO ch // my insert query...
VALUES(" +"'" + item +"'," + year +"," + amount +"," + id +");");
}
I am automating a product using Robotium. In a module I have to validate the data derived.
For that I am using this code:
class sharefirstlevel {
public void A {
for(int k=1;k<=4;k+=2) {
ExpectedResult = solo.clickInList(k);
for (int i = 0; i < ExpectedResult.size(); i++) {
Actualvalues[i] += ExpectedResult.get(i).getText().toString() + " ";
solo.scrollListToLine(0, k);
ExpectedResult=solo.clickInList(1);
Actualvalues[i] += ExpectedResult.get(i).getText().toString() + " ";
ExpectedResult = solo.clickInList(2);
Actualvalues[i] += ExpectedResult.get(i).getText().toString() + " ";
Log.d("xyz","Values of the Strings are"+Actualvalues[i].toString());
}
}
}
}
Its extracting the values selected to an array.
Now when its derived, to validate I am using this code:
class sharedLevel {
public void B {
for(int i=0; i <= sharefirstlevel.Actualvalues.length; i++) {
Log.d("xyz","Values are:"+sharefirstlevel.Actualvalues[i]);
actual=solo.searchText(sharefirstlevel.Actualvalues[i]);
assertEquals(expected, actual);
Log.d("xyz","Values are:"+sharefirstlevel.Actualvalues[i]);
}
}
}
But the thing is in the first part of code proper values are extracted to the Array.
In the second part of code when I am passing the array values, I am not getting the values but the memory allocation object. Hence the test case is failing.
Please help me. Am at a fix !!
How about using
assertTrue(Arrays.equals(expected, actual));
EDIT: This answer is for the question for which the bounty was raised and not the edited question (https://stackoverflow.com/posts/18334315/revisions)
I solved the Problem. The change which I had to make in Class B was
for(int i=1;i<sharefirstlevel.Actualvalues.length;i++){
Log.d("Pratibha","Values are:"+sharefirstlevel.Actualvalues[i]);
actual=solo.searchText(sharefirstlevel.Actualvalues[i]);
assertEquals(expected, actual);
Log.d("TAG","Values are:"+sharefirstlevel.Actualvalues[i]);
}
And hence I am getting the values of the array in class B. Because the index started from 0, and I din't have any text values at 0th position, It was returning garbage values.
Thanks all for the responses.
I can not get SQLite to support my begin/end transaction surrounding multiple inserts.
Multiples INSERTs : 2500ms
Using BEGIN and COMMIT : 90ms
Using SELECT and UNION : 40ms
So I looked using begin and commit. What am I doing wrong?
// pseudocode:
ArrayList<Integer> iList = new ArrayList<Integer>();
for (int i = 1; i <= 500; i++) {
iList.add(i);
}
Collections.shuffle(iList);
StringBuilder sb = new StringBuilder("begin transaction;");
for (Integer i: iList) {
sb.append("insert into \"t_order\" (qid) values(");
sb.append(i);
sb.append(");");
}
sb.append(" end transaction;");
// from docs: http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#execSQL(java.lang.String)
// Execute a single SQL statement that is NOT a SELECT or any other SQL statement that returns data.
m_db.execSQL(sb.toString());
OK, I did a bit more research and it seems that "Multiple statements separated by semicolons are not supported." What can I do instead to insert and preserve insert order?
Start a transaction, execute each of the INSERTs on separate execSQL() calls, and then commit the transaction.
You don't need to cluster the INSERTs together in the same execSQL() call.
Use the SQLiteDatabase.beginTransaction() and SQLiteDatabase.endTransaction() methods and issue your execSQL call(s) between them. It would also be better style to use a ContentValues structure instead of doing your own string concatenation:
ContentValues cv = new ContenValues();
m_db.beginTransaction();
try {
for (Integer i: iList) {
cv.put("qid", i);
m_db.insert("t_order", null, cv);
}
m_db.setTransactionSuccessful();
} finally {
m_db.endTransaction();
}
Have a look at the official Android documentation on beginTransaction(). Replace the "..." portion with a loop doing a separate execSQL() call -- there is no need to truncate the statements together in one buffer.
Also, it's often worth it to use a prepared statement. Prepare the statement, begin the transaction, loop for each item binding and executing the statement and finally commit.
This may help :
public void putAll(Context context, LinkedList<HANDLEDOBJECT> objects) {
if (objects.size() < 1 || objects.get(0) == null)
return;
Log.i("Database", "Starting to insert objects to " + getTableName());
List<String> insertCommands = new ArrayList<String>();
int t = 0;
while (t < objects.size()) {
int k = 0;
StringBuilder sb = new StringBuilder();
sb.append("INSERT OR REPLACE INTO ").append(getTableName())
.append("('k', 'v') ");
for (t = t + 0; t < objects.size() && k < 450; t++) {
k++;
if (t % 450 != 0)
sb.append("UNION ");
sb.append("SELECT " + objects.get(t).getId())
.append(" AS k, ")
.append("'"
+ GsonSerializer.getInstance().toJson(
objects.get(t), getHandledObjectType())
+ "'").append(" AS v ");
}
insertCommands.add(sb.toString());
}
for (String insertCommand : insertCommands)
SQLiteClient.getConnetion(context).execSQL(insertCommand);
Log.i("Database", "Successfully inserted " + t + " objects to "
+ getTableName() + "!!!");
System.gc();
}
String[] temp = new String[adapter.getCount()];
for(int i = 0; i < adapter.getCount(); i++)
temp[i] = adapter.getItem(i).toString();
List<String> list = Arrays.asList(temp);
Collections.sort(list);
adapter.clear();
comment = new Comment();
for(int i = 0; i < temp.length; i++)
{
comment.setComment(temp[i]);
System.out.println("comment is: " + comment.getComment());
adapter.insert(comment, i);
System.out.println("adapter is: " + adapter.getItem(i));
}
for(int i = 0; i < adapter.getCount(); i++)
System.out.println(adapter.getItem(i));
The code above performs the sorting of the ArrayAdapter which is typed ; a helper class as I am using SQLiteHelper and SQL database.
Ok so I verify, after clearing all data within the ArrayAdapter, that the data is added within a lexicographic sorted order.
However, by the time I reach the final for loop to verify this, the ArrayAdapter has replicated the last item in the list at every index. This is weird and makes no sense to me. Of course this is also reflected on the screen.
Can you provide assistance to understand what is going please?
You are using the same instance of 'Comment' throughout the ArrayAdapter. Hence, all positions of the ArrayAdapter have the exact same 'comment' object reference. This single instance has been set to the final string from the original list and so all ListView items will look the same. The solution is to move the instantiation of 'comment' into the for loop to create a unique 'comment' instance for each adapter position. I've also slightly optimized your code.
// -- Count used repeatedly, particularly in for loop - execute once here.
int orgCount = adapter.getCount();
String[] temp = new String[orgCount];
for(int i = 0; i < orgCount; i++)
temp[i] = adapter.getItem(i).toString();
List<String> list = Arrays.asList(temp);
Collections.sort(list);
// -- Prevent ListView refresh until all modifications are completed.
adapter.setNotifyOnChange(false);
adapter.clear();
for(int i = 0; i < temp.length; i++)
{
// -- Instantiation moved here - every adapter position needs a unique instance.
comment = new Comment();
comment.setComment(temp[i]);
System.out.println("comment is: " + comment.getComment());
// -- Changed from insert to add.
adapter.add(comment);
System.out.println("adapter is: " + adapter.getItem(i));
}
for(int i = 0; i < adapter.getCount(); i++)
System.out.println(adapter.getItem(i));
// -- Auto notification is disabled - must be done manually.
adapter.notifyDataSetChanged(true);
// -- All modifications completed - change notfication setting if desired.
adapter.setNotifyOnChange(true);
EDIT
Also, since you're inserting/adding one at a time, you might want to delay notifyDataSetChanged from executing until after all modifications are completed. This will prevent the ListView from refreshing on every modification. I've included it in the code above.
call adapter.notifyDataSetChanged() when all modification are done..