I am trying to update Notes in the room database in My UpdateActivity But it does not update in the database it does not give an error(Works fine) but does not update data in database. Here is UpdateActivity. My log value gives the correct result that I typed in EditText But did not update in the Database.
package com.example.keepnotes;
import static android.content.ContentValues.TAG;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import java.util.Objects;
public class UpdateActivity extends AppCompatActivity {
DatabaseHelper databaseHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_update);
Toolbar toolbar_add = findViewById(R.id.toolbar_update_activity);
setSupportActionBar(toolbar_add);
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
toolbar_add.setNavigationIcon(R.drawable.back_button);
toolbar_add.setNavigationOnClickListener(view -> onBackPressed());
EditText title = findViewById(R.id.update_activity_title);
EditText text = findViewById(R.id.update_activity_text);
Button updateBtn = findViewById(R.id.Update_button);
databaseHelper = DatabaseHelper.getDatabase(UpdateActivity.this);
String titleText = "";
String bodyText = "";
Bundle extras = getIntent().getExtras();
if (extras != null) {
titleText = extras.getString("title");
bodyText = extras.getString("text");
}
title.setText(titleText);
text.setText(bodyText);
updateBtn.setText(R.string.update);
Notes notes = new Notes(titleText,bodyText);
updateBtn.setOnClickListener(view -> {
notes.setTitle(title.getText().toString());
notes.setText(text.getText().toString());
databaseHelper.notesDao().updateNotes(notes);
Log.d(TAG, "onCreate: " notes.title notes.text);
finish();
});
}
}
I think there is any problem in initializing Notes
Notes notes = new Notes(titleText,bodyText);
I initialized like this in my activity.
here is Notes class.
package com.example.keepnotes;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;
@Entity(tableName = "notesTable")
public class Notes {
@PrimaryKey(autoGenerate = true)
public int id;
@ColumnInfo(name = "title")
public String title;
@ColumnInfo(name = "text")
public String text;
Notes(int id, String title, String text) {
this.id = id;
this.text = text;
this.title = title;
}
@Ignore
Notes(String title, String text) {
this.text = text;
this.title = title;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
here is NotesDao class
package com.example.keepnotes;
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Update;
import java.util.List;
@Dao
public interface NotesDao {
@Query("SELECT * FROM notesTable")
List<Notes> getAllNotes();
@Query("SELECT * FROM notesTable")
LiveData<List<Notes>> findAllNotes();
@Insert
void addNotes(Notes note);
@Update
void updateNotes(Notes note);
@Delete
void deleteNotes(Notes note);
}
How can I resolve this?
CodePudding user response:
As mentioned in the comments, you will need the primary key (probably an integral id) of the Notes
entry you want to update.
It looks like you are using putExtra
to pass information about an existing Notes
object that lives in a different Activity
. If that existing Notes
object (call it noteToUpdate
) was retrieved from the database, it should contain the primary key you need. You can add another key/value pair to the Intent
in the original Activity
with something like putExtra("id", noteToUpdate.id)
. Then, in the UpdateActivity
, you can use something along the lines of noteId = extras.getString("id")
to retrieve the id.
Once you have this noteId
, you can replace Notes notes = new Notes(titleText, bodyText);
with a call to a constructor that accepts an id. Alternatively, you could write something like notes.setId(noteId)
after the object is constructed. With the primary key now set correctly, the updateNotes
call should work.
Edit: if I misinterpreted your comments and there is no id field (or similar), please share the Notes
entity structure and primary key.
CodePudding user response:
There are two main ways to update with Room via an @Dao annotated interface or abstract class. You can use the convenience update method which is used by using the @Update
annotation. The other way is to use an UPADTE SQL statement.
Using @Update
If you use the @Update
annotated function then you pass the object to be updated to the function. Room then builds the UPDATE SQL on your behalf. However to ensure that the correct row(s) in the database are updated and not all rows (which could be a disaster), Room uses the value of the field(s) that make up the primary key (the field annotated with @PrimaryKey
or fields using the primaryKeys parameter in the @Entity annotation).
The likely cause of your issue is that neither the titleText nor the bodyText are, or together form, the primary key and as such the primary key is a default value (very often 0 either explicitly or implicitly if the primary key is a java primitive such as long or int) and as such there is no row with such an id to be updated. In which case nothing is updated which is not an error as far as SQLite is concerned.
So if you have
@Update
void update(Notes note);
Then the generated SQL will be something like
UPDATE notes SET titleText='the_value_extracted_from_the_titleText_field_of_the_passed_Notes_object', bodyText = 'the_value_extracted_from_the_bodyText_field_of_the_passed_Notes_object' WHERE the_primaryKeyField='the_value_from_the_primaryKeyFields_of_the_passed_Notes_object'
- where
the_value_from_the....
is an explanation of the value not the actual value.
If this is the issue then to use the @Update convenience method you need to set the field or fields that form or forms the primary key. e.g. notes.setId(the_respective_id);
before doing the update.
The convenience method will also returns an integer that will have the number of rows that have been updated.
So if you have
@Update
int update(Notes note);
and then use :-
if (databaseHelper.notesDao().updateNotes(notes) > 0) {
.... do something here if you want to indicate successful update
} else {
.... do something here if you want to indicate that nothing was updated
}
Using @Query
An alternative approach could be to use the second method, i.e. supply your own UPDATE statement via an @Query such as:-
@Query("UPDATE notes SET titleText=:newTitleText, bodyText=:newBodyText WHERE titleText=:originalTitleText AND bodyText=:originalBodyText;")
void update(String newTitleText, String newBodyText, String originalTitleText, String originalBodyText);
where original.... would be the values as obtained from the intent extras.
IMPORTANT NOTES
- If the combination of the originalTitleText and originalBodyText values is not unique then multiple rows would be updated.
- If you know that titleText would be a unique value for every row then you could just use
WHERE titleText="originalTitleText
- A primary Key MUST be unique and therefore why using the primary is recommended for the WHERE clause of the UPDATE.
- of course you could make the other columns or combinations have a unique index but that is beyond the cope.
- There is an exception (known SQLite feature/bug), that Room doesn't allow to be used in that NULL is considered a unique value but the use of IS NULL will indicate any NULL and likewise IS NOT NULL will indicate no NULLs
- The number of updated rows is not returned using this method