I have looked at the plethora of similar topics for the past couple days but none seem to help my actual situation or maybe it's just my inexperience.
I have a simple application that performs CRUD operations. I can successfully enter new rows into the table as well as delete them, however something is wrong with my update code and I can't find why. What has me puzzled is it worked once, then never did again regardless if I create new entries or delete the database entirely and start again. Isolating what I think the relevant code would be the operation flow is as follows.
The individual items are inside a RecyclerView and are sent from an inner class to the activity to be edited and updated:
public void onBindViewHolder(#NonNull ContactViewHolder holder, int position) {
final String contactName = mCursor.getString(mCursor.getColumnIndex(ContactEntry.COLUMN_NAME));
final int contactNumber = mCursor.getInt(mCursor.getColumnIndex(ContactEntry.COLUMN_PHONE_NUMBER));
final String contactMail = mCursor.getString(mCursor.getColumnIndex(ContactEntry.COLUMN_EMAIL));
final int currentPosition = position;
holder.mEditContact.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(mContext, ContactUpdate.class);
intent.putExtra(CONTACT_POSITION, currentPosition);
intent.putExtra(EXTRA_NAME, contactName);
intent.putExtra(EXTRA_PHONE, contactNumber);
intent.putExtra(EXTRA_MAIL, contactMail);
mContext.startActivity(intent);
}
});
Then I get them in the retrieving class and organise the values into the appropriate EditText views. I'm sure there is a more efficient way but I'm still learning:
Intent intent = getIntent();
mPosition = intent.getIntExtra(ContactRecyclerAdapter.CONTACT_POSITION, 0);
mContactName = intent.getStringExtra(ContactRecyclerAdapter.EXTRA_NAME);
mContactPhone = intent.getIntExtra(ContactRecyclerAdapter.EXTRA_PHONE, 0);
mContactMail = intent.getStringExtra(ContactRecyclerAdapter.EXTRA_MAIL);
mUpdateName.setText(mContactName);
mUpdatePhone.setText("" + mContactPhone);
mUpdateMail.setText(mContactMail);
Lastly my method to update the row:
private void updateData() {
String name = mUpdateName.getText().toString();
String getPhone = mUpdatePhone.getText().toString();
int phone = Integer.parseInt(getPhone);
String mail = mUpdateMail.getText().toString();
SQLiteDatabase db = new ContactOpenHelper(this).getWritableDatabase();
ContentValues values = new ContentValues();
values.put(ContactEntry._ID, mPosition);
values.put(ContactEntry.COLUMN_NAME, name);
values.put(ContactEntry.COLUMN_PHONE_NUMBER, phone);
values.put(ContactEntry.COLUMN_EMAIL, mail);
String selection = ContactEntry._ID + " LIKE ?";
String[] selectionArgs = { String.valueOf(mPosition)};
db.update(ContactEntry.TABLE_NAME, values, selection, selectionArgs);
db.close();
startActivity(new Intent(this, ContactList.class));
}
What is happening is the row is not being updated. Currently I have three mock entries entered. I put a break point at the update() line to try and find out what is happening. The original name for the this entry is "ted" and it's the third in the list. If I edit the EditText field and run the updateData() method, when the break point is hit it correctly shows the edited value as well the correct position of 2. However the database doesn't actually update. I am clearly misunderstanding how something works here.
To avoid bloat I have only included what I think is pertinent, but if anymore info is required then I'm happy to add.
Lastly here is a screen shot of the debugger at the break point showing what I perceive to be the correct information and where I'm completely confused as to why it is not working (I added a bunch of g's on the end of the name "ted" just to test if it would work).
Chnage your call to update as below
int count = db.update(ContactEntry.TABLE_NAME, values, selection, selectionArgs);
where count shows the number of the rows afftected with the update function, this would help you know exactly if there was any updated row or not.
Note :-We use like when, sometimes, you don’t know exactly the complete keyword that you want to query. For example, you may know that your most favorite song contains the word,elevator but you don’t know exactly the name.
If you know the exact value try to use:-
String selection = ContactEntry._ID + " =? ";
String selection = ContactEntry._ID + " LIKE ?";
String[] selectionArgs = { String.valueOf(mPosition)};
Update this above code to this below code
String selection = ContactEntry._ID + " = ?";
String[] selectionArgs = { String.valueOf(mPosition)};
You want to update an exact row. But 'LIKE' keyword mostly uses for searches.
Besides, You are opening your activity when you update your data. Update or insert in database takes some time. When your next activity start, database may not finish its write operation. It could lead you to see the previous data. Make sure your database is updated and then update the view.
See your database from emulator that database has the new value or not. Then do the further work.
Try to delete you _Id from contentValues:
//values.put(ContactEntry._ID, mPosition);
I think you can't change PRIMARY_KEY, you say what line you want to update in:
String[] selectionArgs = { String.valueOf(mPosition)};
I have now solved this particular problem and the answer was quite simple and a little embarrassing. I was trying to use the cursor position for the row ID not realising that the database isn't using a zero-base index like the cursor, hence the primary key was not matching.
As I am using a RecyclerView I added the following line to my onBindViewHolder and passed the variable to my update activity which then could be used in the selectionArgs
final long id = mCursor.getLong(mCursor.getColumnIndex(ContactEntry._ID));
Related
I have a feed containing posts that are currently ordered by "updatedAt". My original intention was to push up posts to the top of the feed which were last replied to (I do this by incrementing a "replyCount" field in each post when a user leaves a comment), not totally cognizant of the fact that another field, "likeCount" is also being updated when user's "like" a post. I would still like to push those posts that were recently "replied to" to the top of the feed, but do not at the expense of the weird UX behavior that associated with liking posts pushing them up as well. I'm not sure how to separate the two.
What should I do here? Can I maybe add another column called "lastReplyCountTime" and then sort queries based on that? Maybe set lastReplyCountTime for all posts to the current time when saved to the database, and then only update that value when a post receives a reply?
String groupId = ParseUser.getCurrentUser().getString("groupId");
ParseQuery<ParseObject> query = new ParseQuery<>(ParseConstants.CLASS_POST);
query.whereContains(ParseConstants.KEY_GROUP_ID, groupId);
/*query.addDescendingOrder(ParseConstants.KEY_CREATED_AT);*/
query.orderByDescending("updatedAt");
query.findInBackground((posts, e) -> {
if (mSwipeRefreshLayout.isRefreshing()) {
mSwipeRefreshLayout.setRefreshing(false);
}
if (e == null) {
// We found messages!
mPosts = posts;
String[] usernames;
usernames = new String[mPosts.size()];
int i = 0;
for(ParseObject post : mPosts) {
usernames[i] = yeet.getString(ParseConstants.KEY_SENDER_NAME);
i++;
}
FeedAdapter adapter = new FeedAdapter(
getListView().getContext(),
mYeets);
setListAdapter(adapter);
}
});
}
You have 2 options:
Like you suggested you can create another date property let's call it sortedUpdatedAt and update it with the current date each time you are updating the relevant values
If you still want to use updatedAt you can wrap your like object in a separate parse object (class). This class will be saved as a relation in the parent class and then each time the user "like" you can just update only this class and not the whole object. This way the updatedAt of your parent object will not be changed.
I think that option 1 is great since it's not so complicated and you can do it very quick.
This is my first question here and I hope I am not repeating someone else's question. I will try and explain the problem as much as I can in the next few lines. Pardon my English if its really bad .
So I have here a JTable in which I would like to retrieve values from a database. So far I can add 1 value and I know why this is. The question is . How do I add multiple values to this table ?
This is the method I use in my operations to find a gun in a specific shop with its quantity
public ResultSet gunSearch(String id, int qty, int storeId) {
try {
String s = "SELECT gunID, gunName AS \"Gun Name\", gunPrice AS \"Price\", SellCost AS \"Cost\", availableQty AS \"Amount Available\", "+qty+" AS \"Quantity\" FROM Guns WHERE gunId = '" + id + "'AND storeId='"+storeId+"'";
pstmt = conn.prepareStatement(s);
rset = pstmt.executeQuery(s);
} catch (Exception ex) {
System.out.println("Error here at searchByProdId Operation "+ex);
}
return rset;
}
For my GUI I use the following code to display the information entered by the user
public void actionPerformed(ActionEvent e){
if(e.getSource().equals(enterBtn)){
String gunID = gunIdText.getText();
int qty = Integer.parseInt(quantityText.getText());
table.setModel(DbUtils.resultSetToTableModel(op.gunSearch(gunID, qty, storeId)));
Whenever I click the Enter button the column of data is retrieved from the database. However if I re-enter another gunId and quantity , the previous column disappears and the new column of data is retrieved from the database.
How could I possibly , enter couple of different gunId's and quantitie's into the JTable ?
Your gunSearch method only returns one result. You then completely recreate the TableModel from this one result, erasing whatever you had in the old model.
You'll need to concoct a new method that can take a Collection<String> (a collection of gun ids) and return a row for each id provided.
Alternatively, you can create a method that adds a gun to an existing TableModel rather than recreating the whole model from scratch every time. It depends on how you want the application to work, which option is better.
What I am trying to do is retrieve an ArrayList from another database manager class. Unfortunately all I can do because the manager class cannot work statically is create an instance in another class, then call the method. Then I got myself into passing that same instance into the method which asked for an SQLiteDatabase object. Now I've worked myself into a bind of confusion, when all I really want is to do is retrieve the arraylist to display a listview of elements from an SQL column.
EDIT: My post lacked clarity, so I'll try to specify exactly what is going wrong and what I am trying to accomplish here:
In a display (output) activity, I am trying to use a ListView to display elements contained in an SQL database. Currently, I am only focusing on one column (Assignment Names). My approach involved using a get method built into the database manager class, but because you cannot reference that method statically, I tried to use the method by creating an instance of that manager class. This would return an ArrayList of Inputted objects (each containing a name). It seemed to have worked, but when running the program, the LogCat protested that I was calling getDatabase recursively. After looking online, people recommended that I fix the issue by changing the method to ask for (SQLiteDatabase db) as parameters so the same database gets tossed around in the manager. Now I get confused here-- I'm not sure what to pass into this method from the display activity. It also doesn't help that from what I've heard from the comments, my get method doesn't traverse the SQL database properly. If you can solve this puzzle THANK YOU!
I'll post my code for diagnosis, hopefully an outside view will show exactly what's wrong with everything I'm trying here.
public Cursor getAssignmentNames(SQLiteDatabase db) {
return db.query(false, ASSIGNMENT_TABLE, COLUMN_TITLES,
" WHERE " + ASSIGNMENT_NAME + " ", null, null, null, " ORDER BY "+ASSIGNMENT_URGENCY_RATING, null);
}
/
public ArrayList<Inputted> getListOfAssignments (SQLiteDatabase db) {
Cursor names = getAssignmentNames(db);
ArrayList<Inputted> assList = new ArrayList<Inputted>();
names.moveToFirst();
while (!cursorsAreAfterLast(names) ) {
int go = 0;
assList.add(new Inputted(names.getString(go))
names.moveToNext();
go++;
}
return assList;
}
/
DBRecordsLayer assignmentRecords = new DBRecordsLayer(this,
"assignment.db", null, 1);
ArrayList<Inputted> assList = DBRecordsLayer.getListOfAssignments(assignmentRecords);
Your code is a bit confusing... In each iteration of the while loop, you are incrementing the cursor (names.moveToNext()); You are also incrementing go.
The result would be:
1st iteration: You are taking the data from the first column of the first query
2nd iteration: You are taking the data from the second column of the second query
etc...
I'm assume that you want to be reading data from the same column of the database for each iteration.
try this:
public ArrayList<Inputted> getListOfAssignments (SQLiteDatabase db) {
Cursor names = getAssignmentNames(db);
ArrayList<Inputted> assList = new ArrayList<Inputted>();
names.moveToFirst();
columnContainingStringToSendToInputtedConstructor = x; //replace the x with column you need from your table
while (!names.isAfterLast()) {
assList.add(new Inputted(names.getString(columnContainingStringToSendToInputtedConstructor));
names.moveToNext();
}
}
Let's say I make the following cursor to get the call log of someone:
String[] strFields = {
android.provider.CallLog.Calls.NUMBER,
android.provider.CallLog.Calls.TYPE,
android.provider.CallLog.Calls.CACHED_NAME,
android.provider.CallLog.Calls.CACHED_NUMBER_TYPE
};
String strOrder = android.provider.CallLog.Calls.DATE + " DESC";
Cursor mCallCursor = getContentResolver().query(
android.provider.CallLog.Calls.CONTENT_URI,
strFields,
null,
null,
strOrder
);
Now how would I go about deleted the ith item in this cursor? This could also be a cursor getting list of music, etc. So then I must ask - is this even possible? I can understand for certain cursors that 3rd party apps wouldn't be allowed to delete from.
Thanks.
Sorry mate you can't delete from a cursor.
You must either use your ContentResolver or a SQL call of some sort..
You can to a trick with a MatrixCursor. With this strategy, you copy the cursor, and leave out the one row you want to exclude. This is - obviously, not very efficient for large cursors as you will keep the entire dataset in memory.
You also have to repeat the String array of column names in the constructor of the MatrixCursor. You should keep this as a Constant.
//TODO: put the value you want to exclude
String exclueRef = "Some id to exclude for the new";
MatrixCursor newCursor = new MatrixCursor(new String[] {"column A", "column B");
if (cursor.moveToFirst()) {
do {
// skip the copy of this one ....
if (cursor.getString(0).equals(exclueRef))
continue;
newCursor.addRow(new Object[]{cursor.getString(0), cursor.getString(1)});
} while (cursor.moveToNext());
}
I constantly battle with this; trying to make my apps with cursors and content providers only, keeping away from object mapping as long as I can. You should see some of my ViewBinders ... :-)
In the app we are putting together I am trying to update rows from different Activities but it is throwing an error or not updating anything because I can't seem to get the current rowId once I move from one activity to the next. Any thoughts would be great.
This comes from the Activity:
Cursor value;
db.open();
long rowId = value.getLong(value.getColumnIndex("_id"));
boolean id = db.updateA(rowId, a1, a2, a3, a4);
db.close();
If I set the "rowId = 1" it updates that row just fine but I want to get the row that was just created in a different activity.
This is in the DBHelper file:
public boolean updateA(long rowId, String a1,String a2, String a3, String a4) {
ContentValues args = new ContentValues();
args.put(C_A1, a1);
args.put(KEY_A2, a2);
args.put(KEY_A3, a3);
args.put(KEY_A4, a4);
return db.update(TABLE, args, KEY_ROWID + "=" + rowId, null) > 0;
}
If you need to update the record I would suggest storing the record upon creation in a data object in memory and passing that to the other Activity that needs to do the update. The data object should have a property for its own ID, so you can just use that.
Not having a reference to the record you need to update will be a disaster. Also, if you know you always need to update the record, why don't you just do it on insert?
I don't get that.
You have an activity A that opena a DB, updates a row and closes the DB. This is done with the help of SQLiteOpenHelper class.
Now you move to activity B and now what? Post your primary key (you know it, you used it an A) with putExtra to B (or just put the whole row to B). If you put the rowid to B you can open, reread the row, update if needed and close again. If you just put the whole row to B, well that's all you need to do - but I wouldn't like that (e.g. what happens if B crashes?).
If you update in both activities without knowledge what both activities did (and without re-reading the rows) it's pure luck what you end with.
Try this:
return db.update(TABLE, args, KEY_ROWID + "='" + rowId + "'", null)