Room database onConflict = OnConflictStrategy.REPLACE not working - android

I am working on Room database and trying to insert list of items(eg. list of Quotes which contains author name and a quote in my case).
Following is the code I am using:
// view model
BaseApp.daoInstance?.appDao()?.insertQuotes(response!!)
// dao
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertQuotes(listData: MutableList<Quote>)
When I try to insert the same data again, it always inserts as a new data instead of replacing with the current items.
I have researched a lot for this OnConflictStrategy.REPLACE but could not find any proper answer.
Is there anyone facing the same issue and found solution or am I doing anything wrong?
Thank you in advance...!!!

Room, will not check and compare if you have the quote already in the DB.
What it will do is look if the primary key already exists in the DB if it does, Room will replace all old data with the new one.
In your case, you are not specifying an ID so the DB is generating a unique one for you.
What you should do is create a Query that will search for this quote in the DB something like this:
#Query("SELECT * from quote_table WHERE author = :author AND quote = :quote")
List<Quote> getQuoteByAuthorAndQuote(string author, string quote);
This should return a list with a single quote if one is found and empty if it does not exist.
If you would like to override the old one just update the data in the Quote POJO and insert it to the DB using Room.

Have you tried to index your main column and mark it as unique?
#Index(value = {"quote"}, unique = true)}

It suppose to search for your unique or primary key and compare then replace, while in your case you're not defining an ID so it will generate a unique one for you, so it won't even compare and will consider any item as a new one.
Write a new query and function to solve this issue.

When I had same problem, changes in imports did the trick, added following import:
import androidx.room.*;

Related

cant find out how to read a row from room database

I am new to Android studio, especially in room database.
I can't find out how to read a row from room database
//in dao
#Query("SELECT * from qarindosh_table LIMIT 1")
Qarindosh getAnyQarindosh();
I couldn't find out how to read a row. Please help.
Room database is working.
This is how you do it
#Query("SELECT * FROM qarindosh_table")
List<ModelClass> getAllItems();
If I understand you correctly, you wish to read 1 specific row from a database. In order to do that, you need to query by primary key, usually named id in the Entity. Something like that:
#Query("SELECT * FROM qarindosh_table WHERE id=(:id)")
Qarindosh loadQarindoshById(int id);

Room not returning duplicates

So I have a room database all set up, everything is fine, so I can make queries and inserts, delete etc no problems, however i've just run into a situation where id like to return entries by their Ids and duplicates should be allowed, however room is removing the duplicates, so for instance I send it a list of ids say <1,2,3,2,3> and it returns items by their ids but only sends me <1,2,3> removing the duplicate entries. The query I'm making is below (btw complete noob at sql)
#Query("SELECT * FROM card WHERE cardId IN(:cardId)")
LiveData<List<Card>> getCardsByIds(List<Integer> cardId);
Im using it via a repository I created (just a level of abstraction) and calling this repo from a ViewModel, this ViewModel has a mutable live data integer list containing the ids and using a SwitchMap I get the latest live data. ill include the relevant pieces below
CARD REPO calls my Daos method like this
public LiveData<List<Card>> getCardsByIds(List<Integer> cardIds){
return cardDao.getCardsByIds(cardIds);
}
ViewModel calls for them
private MutableLiveData<List<Integer>> cardIds;
//** constructor etc
cards = Transformations.switchMap(cardIds, id -> cardRepository.getCardsByIds(id));
and through the magic of SwitchMap when the cardIds list updates a new query is made and I observe the ViewModel from my fragment. I've debugged it so I know the list of Ids is correct and has the duplicates Ids, but the returned LiveData list is missing the duplicate Ids. any help?
Edit:
The SQLiteDatabase always presents the results as a Cursor in a table format that resembles that of a SQL database.
Source : Google Developer Training
Before the results are returned by the query, the results are stored in a table, and if there are rows with duplicate primary keys, they would be omitted by default.
To achieve what you intend, you can execute a query to find single element by id in loop and append the result to a list.
Updated DAO method:
#Query("SELECT * FROM card WHERE cardId=:cardId")
LiveData<Card> getCardById(Integer cardId);
Update Repository method:
public LiveData<List<Card>> getCardsByIds(List<Integer> cardIds){
List list = new ArrayList();
for(Integer cardId: cardIds){
list.append(cardDao.getCardById(cardId));
}
return list;
}
Hope this helps.
Original Answer:
If id is the primary key of your model, It doesn't allow duplicate data to be entered. Hence while retrieving you might find duplicates missing.
If you have id with duplicate, create another attribute for primary key. (use autogenerate if you don't have any primary key attribute)
A primary key is by default UNIQUE and NOT NULL.

How to get saved id in SugarORM?

SugarORM, in my opinion, is the easiest SQLite library to use and proven to be extremely helpful for junior Android developer like me. SugarORM automatically creates the table and add an AUTO_INCREMENT id column for every java class extending SugarRecord.
Inserting a new row can be as easy as someJavaObject.save(). But how can I get the inserted id once that row is inserted? In PHP I can do something like $id = mysql_insert_id(); after insertion.
I understand that I can just get the id of last row in the table. But the insertion of new row can somehow be very unpredictable. Let's say I have an activity and a service inserting a new row at the same time, I want to avoid getting the wrong id.
Thanks in advance for any help.
The save() method has to return it. Like:
long id = someJavaObject.save()
or try:
someJavaObject.save()
long id = someJavaObject.getId();
As Stan mentioned, save actually returns the id as long value. I used this by today.
If you want to use this for a freshly created row you may do something like this:
Region reg2 = new Region("Graz", 20, 20);
reg1.setId(reg1.save());

GreenDAO groupby clause

I am currently using greenDAO as the ORM for my Android Application. I ran into an issue when trying to execute a GROUPBY clause.
greenDAO does not have API / helper methods for performing groupby clauses, so I decided to use query() or queryRaw() methods available for the AbstractDAO class, where I can pass a valid SQL query. BUT, both these methods return a java.util.List, so what confuses me is that how can I get values of column aliases in the result?
Eg,
SELECT COUNT(ID) AS NUMOFRECORDS, NAME FROM PERSONS GROUP BY AGE
My entity will have NAME and AGE fields, but I created a column alias NUMOFRECORDS, which is not part of the Entity.
Appreciate your help!
This is a alternative solution for your question:
Include the ORDER BY insize of Where.
Ex:
List<Taxi> list = daoSession.getDaoTaxi().queryBuilder().where(new WhereCondition.StringCondition("1 GROUP BY cant_aciento")).list();
I'm stuck with a similar problem. It seems that greenDao doesn't support GROUP BY querys and it won't change in the future, according to what they said here:
GROUP BY is SQL-ish, so stick to SQL. greenDAO is about entities, where GROUP BY is unsupported.

Delete last row using Ormlite

I'm using Ormlite for database operations on my Android App.
In one of the methods, I need to delete the last row in a table. However I m not able to find out how. I'm successfully deleting rows when giving an argument, but in this specific case I don't have arguments.
Here's my attempt:
LottoDatabaseHelper helper = OpenHelperManager.getHelper(getApplicationContext(), DatabaseHelper.class);
//You get helper
Dao dao = helper.getDao(MyTable.class);
//get your Dao
DeleteBuilder<MyTable, Integer> deleteBuilder = dao.deleteBuilder();
//How can I specify last row here?
deleteBuilder.delete();
Thank you for your help
I haven't used Ormlite .. here is a simple solution which can use with any database ... As you said you can delete a row by passing argument...
try this..
1. Find the last id using the query..
eg. SELECT id FROM table_name ORDER BY id DESC LIMIT 1
// will return the last row id
2. then pass the id as a parameter to delete ...

Categories

Resources