Objectify paging with Cursors - java

I have this method in my RPC service:
#Override
public Entrata[] getEntrate(int from, int to) {
List<Entrata> data = entrateDao.list();
return data.toArray(new Entrata[0]);
}
As you can see, I am not using the two parameters, which, in a SQL world, I would use as LIMIT and OFFSET.
It's not completely clear what I have to do now, I started reading this:
http://code.google.com/p/objectify-appengine/wiki/IntroductionToObjectify#Cursors
I think I have to do a query.startCursor(<my_"from"_parameter>)
Then iterate for "TO" times, the page size.
All right? Can you help me with some snippets? :)

From docs: Cursors let you take a "checkpoint" in a query result set, store the checkpoint elsewhere, and then resume from where you left off late
As you need just limit/offset, you have to use limit() and offset() method of Objectify Query. Like:
ob.query(Entrata.class).limit(to - from).offset(from)
Or, when you have cursor:
String cursor = // get it from request
Query<Entrata> query = ob.query(Entrata.class);
Query q = query.startCursor(Cursor.fromWebSafeString(cursor));
q.limit(x);
QueryResultIterator<Entrate> iterator = query.iterator()
List<Entrate> data = // fetch data
String newCursor = iterrator.getStartCursor().toWebSafeString()
return new EntrataListWithCursor(data, cursor);

I just want make sure you don't have any errors in your code since you can copy and past the Igor Artamonov code.
Here is a cleaner code from Objectify Wiki with less errors and some documentation:
// create the query and set the limit to 1000
Query<Car> query = ofy().load().type(Car.class).limit(1000);
// Here you get the cursor (if exists) from the request
// For the first request, i-e the first page, this parameter(cursor) will be null
String cursorStr = request.getParameter("cursor");
// Here you check if cursor is not null and not empty
// If so, we start our query from the last check point
if (cursorStr != null && !cursorStr.isEmpty())
query = query.startAt(Cursor.fromWebSafeString(cursorStr));
// We need this variable to know when we have been loaded all the entries
boolean remaining = false;
QueryResultIterator<Car> iterator = query.iterator();
while (iterator.hasNext()) {
Car car = iterator.next();
... // your code here
// We have found entries, so we set this variable to true.
// That means, we have probably another page to fetch
remaining = true;
}
// If we have found entries, we send the last check point
if (remaining) {
// we take the last check point by calling "toWebSafeString()" from the iterator's cursor
Cursor cursor = iterator.getCursor();
Queue queue = QueueFactory.getDefaultQueue();
queue.add(url("/pathToThisServlet").param("cursor", cursor.toWebSafeString()));
}

Related

How to add key and value dynamically and call the procedure in java (Oracle ADF)

ViewObject VO = getViewObjectFromAMImpl("EOView2", "AppModuleDataControl");
Row[] selectedRows = VO.getFilteredRows("tSelect", true);
int counter = 0;
ADFContext adfCtx = ADFContext.getCurrent();
SecurityContext secCntx = adfCtx.getSecurityContext();
String _user = secCntx.getUserName();
//Date vDate = getMinDate();
java.sql.Timestamp startDate = null;
for (Row r : selectedRows) {
startDate = (java.sql.Timestamp) r.getAttribute("StartDate");
if ("E".equals(r.getAttribute("SrcType"))) {
r.setAttribute("Type","S");
r.setAttribute("UpdatedBy", new Date());
r.setAttribute("LastUpdateDate", new Date());
counter++;
}
}
System.out.println("printing count"+counter);
if (counter == 0) {
JSFUtils.addFacesErrorMessage((String) JSFUtils.resolveExpression("No records Approved."));
} else {
Commit();
JSFUtils.addFacesInformationMessage((String) JSFUtils.resolveExpression(" records Approved successfully."));
AdfFacesContext.getCurrentInstance().addPartialTarget(hearderTableBind);
}
approvePopup.cancel();
From the above code i will get the selected rows with key and value pair. I want to add those rows ( Key and Value) to a list and i need to call the procedure. Could you please tell me which is the best possible way to achive this.
I want to call the procedure with key and value pair( Multiple values will come)
You should read the doc at
https://docs.oracle.com/en/middleware/developer-tools/adf/12.2.1.4/develop/extending-business-components-functionality1.html#GUID-B93C7B79-73C9-4434-B12E-A7E23479969A
However, I fail to understand why you need to call a pl/sql procedure at all.
You should be able to do everything in ADF or call a procedure directly without iterating over the data just to set some values.
It's not a good idea to change values in ADF, then call a procedure and assume that the framework somehow knows the changes. The procedure runs in the DB in a different transaction. ADF doesn't know about changes done in the function. The function doesn't know about the changes done in ADF until you post them to the DB.

Add a missing record into the arraylist if it is not in it

Pardon me as I'm quite a beginner in coding. I have tried researching for ways to add some missing record into the lists but still can't seem to fit it correctly into my code.
I have two ArrayLists with different resultsets. Say, the first one is derived in other method and stored in abcList. This list is then used in my current fixChartStats method as a param.
In my code, I will check for the corresponding record in abcList with the second list I derive from the hql query in fixChartStats method.
If the record corresponds, then I'll do the necessary action as shown below to update the ApprovedCount number etc, else i set it to 0.
How do I go about adding the records that are missing in second list I got into the first arraylist (i.e. abcList)? Can anyone here shed some light? Do let me know if my questions are unclear. Thanks in advance, guys!
private void fixChartStats(List<TAbcModel> abcList, Map<String, Object> param, List<IssueModel> issueList, List<DestModel> destList) throws Exception {
//initialize the hql query
//translate all fields from Object[] into individual variable
firstRow = true;
for (TAbcModel abc : abcList) {
if (abc.getId().getAbcYear() = abcYear &&
abc.getId().getAbcMonthId() = abcMonthId &&
abc.getId().getAbcApplAccnId().getAccnId().equalsIgnoreCase(abcApplAccnId.getAccnId()) {
if (firstRow) {
abc.setApprovedCount(abcApprovedCount);
abc.setCancelledCount(abcCancelledCount);
firstRow = false;
} else {
abc.setApprovedCount(0);
abc.setCancelledCount(0);
}
}else{
// How to do the necessary here
// Below is what I've tried
abcList.add(abc);
}
}
}
When I debug, I noticed that it was added into the list. But soon after it was added, ConcurrentModificationException was thrown.
Create a local list and add missing records to it then add all elements from the local list to the abcList
List<TAbcModel> temp = new ArrayList<>();
in your loop:
} else {
temp.add(abc);
}
after loop
abcList.addAll(temp);

Modifying a large set of objects using JPA / EclipseLink

I need to iterate 50k objects and change some fields in them.
I'm limited in memory so I don't want to bring all 50k objects into memory at once.
I thought doing it with the following code using cursor, but I was wondering whether all the objects I've processes using the cursor are left in the Entity Manager cache.
The reason I don't want to do it with offset and limit is because the database needs to work much harder since each page is a complete new query.
From previous experience once the Entity manager cache gets bigger, updates become real slow.
So usually I call flush and clear after every few hundreds of updates.
The problem here is that flushing / clearing will break the cursor.
I will be happy to learn the best approach of updating a large set of objects without loading them all into memory.
Additional information on how EclipseLink cursor works in such scenraio will be valuable too.
JpaQuery<T> jQuery = (JpaQuery<T>) query;
jQuery.setHint(QueryHints.RESULT_SET_TYPE, ResultSetType.ForwardOnly)
.setHint(QueryHints.SCROLLABLE_CURSOR, true);
Cursor cursor = jQuery.getResultCursor();
Iterator<MyObj> cursorIterator = cursor.iterator();
while (cursorIterator.hasNext()) {
MyObj myObj = cursorIterator.next();
ChangeMyObj(myObj);
}
cursor.close();
Use pagination + entityManager.clear() after each page. Also execute every page in a single transaction OR you will have to create/get a new EntityManager after an exception occurs (ar least with Hibernate: the EntityManager instance could be in an inconsistent state after an exception).
Try this sample code:
List results;
int index= 0;
int max = 100;
do {
Query query= manager.createQuery("JPQL QUERY");
query.setMaxResults(max).
setFirstResult(index);
results = query.getResultList( );
Iterator it = results.iterator( );
while (it.hasNext( )) {
Object c = (Object)it.next( );
}
entityManager.clear( );
index = index + results.getSize( );
} while (results.size( ) > 0);

Trying to compare a HashSet element with an element in a List

I have a HashSet that I created and this is what it contains. It will contain more later on, this is pasted from standard out when I did a toString on it. Just to show the contents.
foo.toString(): Abstractfoo [id=2, serial=1d21d, value=1.25, date=2012-09-02 12:00:00.0]
INFO [STDOUT] price.toString(): Abstractfoo [id=1, serial=1d24d, value=1.30, date=2012-09-19 12:00:00.0]
I have a List that I also have and I need to compare the two. One of the elements in List is:
Bar.toString(): Bar [id=1d21d, name=Dell, description=Laptop, ownerId=null]
Here is what I am trying to do...
Bar contains all of the elements I want foo to have. There will only be one unique serial. I would like my program to see if an element in the list that is in HashSet contains the id for bar. So serial == id.
Here is what I've been trying to do
Removed code and added clearer code below
I've verified the data is getting entered into the HashSet and List correctly by viewing it through the debugger.
foo is being pulled from a database through hibernate, and bar is coming from a different source. If there is an element in bar I need to add it to a list and I'm passing it back to my UI where I'll enter some additional data and then commit it to the database.
Let me know if this makes sense and if I can provide anymore information.
Thanks
EDIT: Here is the class
#RequestMapping(value = "/system", method = RequestMethod.GET)
public #ResponseBody
List<AbstractSystem> SystemList() {
// Retrieve system list from database
HashSet<AbstractSystem> systemData = new HashSet<AbstractSystem>(
systemService.getSystemData());
// Retrieve system info from cloud API
List<SystemName> systemName= null;
try {
systemName = cloudClass.getImages();
} catch (Exception e) {
LOG.warn("Unable to get status", e);
}
// Tried this but, iter2 only has two items and iter has many more.
// In production it will be the other way around, but I need to not
// Have to worry about that
Iterator<SystemName> iter = systemName.iterator();
Iterator<AbstractSystem> iter2 = systemData .iterator();
while(iter.hasNext()){
Image temp = iter.next();
while(iter2.hasNext()){
AbstractPricing temp2 = iter2.next();
System.out.println("temp2.getSerial(): " + temp2.getSerial());
System.out.println("temp.getId(): " + temp.getId());
if(temp2.getSerial().equals(temp.getId())){
System.out.println("This will be slow...");
}
}
}
return systemData;
}
If N is the number of items in systemName and M is the number of items in systemData, then you've effectively built an O(N*M) method.
If you instead represent your systemData as a HashMap of AbstractSystem by AbstractSystem.getSerial() values, then you just loop through the systemName collection and lookup by systemName.getId(). This becomes more like O(N+M).
(You might want to avoid variables like iter, iter2, temp2, etc., since those make the code harder to read.)
EDIT - here's what I mean:
// Retrieve system list from database
HashMap<Integer, AbstractSystem> systemDataMap = new HashMap<AbstractSystem>(
systemService.getSystemDataMap());
// Retrieve system info from cloud API
List<SystemName> systemNames = cloudClass.getImages();
for (SystemName systemName : systemNames) {
if (systemDataMap.containsKey(systemName.getId()) {
System.out.println("This will be slow...");
}
}
I used Integer because I can't tell from your code what the type of AbstractSystem.getSerial() or SystemName.getId() are. This assumes that you store the system data as a Map elsewhere. If not, you could construct the map yourself here.

Retrieving a single column of last row in sqlite/Android using ORDER ID desc limit 1

I'm attempting to create a method that will allow me to retrieve a value from the last row of a database, and then insert it into an EditText field. (This is a value that the user will not change all that often, so it would be helpful if when they do set it, it stays set when they come back to it).
My method, based on a similar method I have for getting the total of a specific column, is as such:
public String getBase() {
Cursor mCursor = mDb.rawQuery(
"SELECT base FROM table constants ORDER ID desc limit 1", null);
if (mCursor.moveToFirst()) {
return mCursor.getString(0);
}
return mCursor.getString(0);
Like I said, I based this on a similar method, which I found after searching around the Internet. I understand most of it, but I have no idea what the 0's in the return statements mean (or the moveToFirst method).
Anyway, in my OnClickListener (the button the user would press to save this value to db), I have the following (editBase is the EditText field I want to populate):
editBase.setText(cDbHelper.getBase());
If I run the program without this statement, it works fine and the value saves to the db. As soon as I try to run it with this, I get a force close. Any suggestions?
Thanks.
EDIT: Thanks for the responses. With some guidance from a friend, I ended up using "ORDER BY... desc limit 1" instead. This was the final method:
public double getBase() {
final double DEFAULT_BASE = 0;
Cursor mCursor = mDb.rawQuery(
"SELECT base FROM constants ORDER BY _id desc limit 1", null);
if (mCursor.getCount() == 0)
return DEFAULT_BASE;
else
mCursor.moveToFirst();
return mCursor.getDouble(0);
1) For querying the DB may be try this one:
https://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html
SQLiteDatabase has query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) method.
At least with this one you don't need to construct your SQL manually.
2) Check the doc for Cursor:
http://developer.android.com/reference/android/database/Cursor.html#getString(int)
0 is a columnIndex.
You are probably trying to update a View when running a job on a separate thread, this almost always triggers a force close.
In this article, Painless Threading, you learn how to break of your long running work into another thread (and how you can "come back" to it). Basically you can tell the GUI thread (or event queue or ui thread) that you need a Runnable to run with access to your controls and views.
private void clicked() {
// called from a click of a button for instance
new Thread(new Runnable() {
public void run() {
// the long running job should be executed on a different
// thread as to not stall the ui thread
runLongWork();
}
}
}
private void runLongWork() {
// this is method running on separate thread
// so we should run a runnable on the ui thread instead to update our view's.
this.runOnUiThread(new Runnable() {
public void run() {
// Now we are back in the ui thread
editBase.setText(cDbHelper.getBase());
}
}
}
As for the other questions Arhimed already answered it partly. When you execute a query to the Sqlite database you get an instance of a class Cursor that sort of is a list of the results or rows that your query fetched. Using the moveToFirst method you position the cursor at the first row of results. You can then get the values from the columns in your query using the getXYZ() methods (for instance getString()) and pass an index of the column that you want. 0 in this case refers to base, the first column in your SQL query.
I you have more than one row you can use the moveToNext method to get the next row, and since it returns a bool stating that it actually "found" a next row, you can use it in a while loop to get all your rows.
while (cursor.moveToNext()) {
// next row of data, use getString, getInt or others
}
Your query altough will always return only one value, since you limit the results to 1, so no need to use the moveToNext. moveToFirst will, like moveToNext, return true if a row was found, and false if there are no more rows available.
Your statement is as follows; you execute a query, move to the first row, and if it was successful return the string from the first column in the query (index starts at zero). If it doesn't find a row, you return the first column as a string, which will probably fail though. You should perhaps return a default value or throw an exception in that case.

Categories

Resources