Storing JSON data from the assets into the DB with Room - android

I have a big JSON file in the assets and I want to store it in the DB using Room.
Right now, my app takes the JSON file and parses it, generating some data models containing the information.
What is the way to insert it into the DB? Is the repository the one to do that? How do I know if the database is empty or that all that info has already been dumped into the DB?
Thanks in advance!

What is the way to insert it into the DB? Using an Insert query in your entity DAO, like:
#Insert
fun insertTickets(vararg tickets: Ticket)
Is the repository the one to do that? This is a matter of structure or your application. If you have a repository, then yes, the repository should be the one speaking with the database.
How do I know if the database is empty or that all that info has already been dumped into the DB? To know if the database is empty you would have to query all tables for data, either by issuing a Query with COUNT(*), like
#Query("SELECT COUNT(*) FROM X")
fun numberOfRecordsInX(): Long
or asking for any one row to see if something is returned. No idea which can be faster:
#Query("SELECT * FROM x ORDER BY rowid LIMIT 1")
fun gimmeAnyRowInX() : EntityX

Related

how to add realm database rows (objects) in design or development phase?

lets say I want to make an app only read data from employee realmObject like
employee: {EmpNo String, EmpName String, DeptNo int, Sal int, comm int }
now I want to add about 1000 employee to realm database to use it in my app.
Is there any way to do this in design / development phase ?
or I have to build another project to add these records?
note: I have the data as csv or json, the important point that I want to add these records by developer not by user, how to do this?
I found the answer after some searching for it.
realm studio offers a way for this.
We can create new realm database file from csv file.
realm Studio>file menu>create realm from> csv.
Or after opening realm file, we can import csv data into current realm database file (one condition is: file name must match realm object in database).
realm Studio>file menu>import data from> csv.

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 DB Upgrade need to write full insert query

Hi I am developing an android app and I am using room DB and I have created one table and now I want to add another table I need to write a migration for that and in-migration I need to write full SQL queries for the new table assume I have more than 20 fields how complex will be the query.
In SQLite, we need to write such complex queries which sometimes becomes complicated to write and find errors So, room DB came to resue but now we need to do the same in the room DB migration. How does it useful then?
If we use SQLite, then if we already added one table and now We want to add another table then we can just uninstall the application and new tables will be generated, but in-room DB this is not a case I tried the same thing but it is still showing me that you need to write a migration for the new table. So, in this case, while developing there will a lot of migration scripts that will be hard to maintain at some point in the future.
How does it useful then I have to write a multiple create queries while developing the app this is a very basic flow in any application.
Once we go to prodution then it makes sense to write migration for every table but not in the developing mode.
How does room DB make developr job eaiser?
I have more than 20 fields how complex will be the query.
It can be very simple as an Entity defines an Object e.g. your 20 columns and to get the 20 columns can be as simple as
#Query(SELECT * FROM thetable)
List<Thetable> getAll();
The above being in an Interface that is annotated with #Dao and all you do in the code is retrieve an instance from the built room database and then use the getAll method which returns a List of Thetable objects. Each with all the member variables populated from the database.
e.g. you could have :-
mMyTheTableDaoObject = mMyBuiltRoomDatabase.getAll();
List<TheTable> myTheTableList = mMyTheTableDaoObject.getAll();
for(TheTable t: myTheTableList) {
int current???? = t.get????();
}
While using standard/non-room then you would have to do something along the lines of :-
SQLitedatabase db = whatever_you_need_to_do_to_get_an_SQLiteDatabase_instance;
Cursor c = db.query("theTable",null,null,null,null,null,null);
ArrayList<TheTable> myTheTableList = new ArrayList();
while(c.moveToNext()) {
currentTheTable = new TheTable();
current.TheTable.setId = c.getLong(c.getColumnIndex("id");
current.TheTable.setNextColumn1 = c.getString("next_column1");
current.TheTable.setNextColumn2 = c.getString("next_column2");
........ another 17 similar lines of code
currentTheTable.setNextColumn20 = c.getString("next_column20");
myTheTableList.add(currentTheTable);
}
for(TheTable t: myTheTableList) {
int current???? = t.get????();
}
If we use SQLite, then if we already added one table and now We want to add another table then we can just uninstall the application and new tables will be generated, but in-room DB this is not a case I tried the same thing but it is still showing me that you need to write a migration for the new table.
Once we go to production then it makes sense to write migration for every table but not in the developing mode.
Rather then migrating simply delete the database (delete the App's data or uninstall the App, the database is stored in the default location (data/data/package_name/databases)) and rerun without changing the version. The database will be created as per the new schema. Perhaps utilising temporary code to load data accordingly.
How does room DB make developr job eaiser?
In Short ROOM generates what is termed as the boilerplate code from relatively simple code e.g the #Query above writes the underlying code to extract the data and build the objects (e.g. the code as above).
Please check the official document:
https://developer.android.com/training/data-storage/room/migrating-db-versions
Actually Room using SQLITE behind the scene. It provide you plethora of other facilities. In case of Migration you have to write full code to create table.
Harsh your question is valid in some way but as you know android is maintaining SQLite database and libraries like room, greendao or even native SQLiteOpenHelper
is handling the transaction with sqllite behind the scene for the developers.
In all the earlier libraries too you have to maintain versions of your database and which fields or tables have been added to your database and write migrations for the version upgrades of the database.
The beauty of room comes in play in how easy they have made the CRUD operations on the SQLite database and getting data wrapped in LiveData or Observable, not that you don't need to write migrations.

How to do search in Room data base?

I have created a room database, and showed my data in a RecyclerView. I know how to add, delete, deleteAll, update data in room data base, but the problem is I don't know how to perform search in room data base?
I have added a search view in the tool bar. But I don't know how to add Queries in NoteDao and the remaining classes, e.g. in my adpter, MainActivity etc.
If you're able to show your Room database in the RecyclerView, this would mean you should know how to use the #Query() tag for fetching your data.
Searching is done using the same #Query tag using the WHERE keyword.
For example, if you wish to find a specific note:
#Query("SELECT * FROM notes WHERE id == :id")
public Note getNote(String id)
However, that's just the simplest way to use WHERE. Frequently, you'll be combining it with other keywords such as IN, LIKE, or BETWEEN.
So for your situation of using a search, you would most likely want to use the LIKE keyword, which can query your database for a field that contains parts of its data that matches the search criteria:
For example:
#Query("SELECT * FROM notes WHERE note_title LIKE :search OR note_message LIKE :search")
public List<Note> getSearchedNote(String search)
This would search your database and return a list of Notes that has either a Note Title or a Note Message that contains the search term you want.

Android Content Provider SQLite Junction Tables

I'm implementing a Content Provider, which is backed by a fairly complex SQLite DB schema. The database has a few junction tables and I'm unsure whether they should be visible to the user of the Content Provider or not.
The parent tables are exposed via the Contract, each one has its own content URI, etc. Now, when inserting data via ContentResolver#applyBatch() method, I create ContentProviderOperation per each table's content URI. So far everything is clear. But my problem is, how should the junction tables be populated, as they don't have their own content URIs?
To illustrate this, here's an example. I have 2 "parent" tables, Movies and Actors. The relationship between them is many-to-many and therefore I have a junction table called MoviesActors.
To insert at one batch I do the following:
List<ContentProviderOperation> operations = new ArrayList<>;
// movie
operations.add(ContentProviderOperation.newInsert(Contract.Movie.ContentUri).withValue("movie_id", "23asd2kwe0231123sa").build());
// actor
operations.add(ContentProviderOperation.newInsert(Contract.Actor.ContentUri).withValue("actor_id", "89asd02kjlwe081231a").build());
getContentResolver().applyBatch(authority, operations);
The junction table MoviesActors should be inserted with a row containing movie_id and actor_id. How do I take care of the junction table in this situation?
The only thing, which comes to my mind is extend the Contract to have content URI pointing to the junction tables and add another ContentProviderOperation, since otherwise, how do you communicate movie_id and actor_id to ContentProvider#applyBatch()?
I rather not expose the junction table to the user of the ContentProvider, but I might be wrong here... perhaps that's how it should be done on Android?
I've searched this topic for days already and haven't found an answer to that.
Any help would be greatly appreciated.
Bonus question:
Is it necessary to expose every single table via the Contract? For instance, when having child tables in one-to-many relationship. I'm specifically referring to Insert/Update/Delete since I know with Query I can simply do a join, but maybe I'm wrong also here.
Thanks a lot!
NOTE: I'm not interested in 3rd party library solutions.
I think you're tackling the problem from the wrong end. You're trying to design an interface to match your database structure, but the interface should come first.
In the first place, the interface should meet all the requirements of your ContentProvider client. If your ContentProvider client needs access to the junction table you'll have to expose it (in some way, see below), otherwise you don't have to. A good interface hides the actual implementation details, so the ContentProvider client doesn't need to care about whether the ContentProvider is backed by an SQLite database, by a bunch of in-memory maps or even a web-service.
Also, you should not think of a ContentProvider just as an interface to a database and the Contract as the database schema. A ContentProvider is much more versatile and powerful than that. The major difference is that ContentProviders are addressed by URIs whereas in SQL you just have table names. In contrast to a table name, a URI has a structure. URIs have a path that identifies the object (or directory of objects) that you want to operate on. Also you can add query parameters to a URI to modify the behavior of an operation. In this respect a ContentProvider can be designed much like a RESTful service.
See below for a concrete (but incomplete) example of a Contract of a simple movie database. This is basically how one would design a RESTful web-service, except for one thing: Just like in your code, movie-id and actor-id are provided by the caller. A real RESTful service would create and assign these automatically and return them to the caller. A ContentProvider can only return long IDs when inserting new objects.
Insert a new movie
insert on /movies/
Values: {"movie_id": <movie-id>, "title": <movie-title>, "year": ...}
Insert a new actor
insert on /actors/
Values: {"actor_id": <actor-id>, "name": <actor-name>, "gender": ...}
Add an existing actor to a movie
insert on /movies/movie-id/actors/
Values: {"actor_id": <actor-id>}
Add an existing movie to an actor:
insert on /actors/actor-id/movies/
Values: {"movie_id": <movie-id>}
Optional: add a new actor directly to a movie:
insert on /movies/movie-id/actors/
Values: {"actor_id": <actor-id>, "name": <actor-name>, "gender": ... }
If no actor with the given id exists, this operation will create the new actor and link it to the movie in a single step. If an actor with this ID already exists an exception would be thrown.
The same could be done the other way round, adding a new movie to an actor.
Delete an actor from a movie
delete on /movies/movie-id/actors/actor-id
or
delete on /actors/actors-id/movies/movie-id
Get all movies
query on /movies/
Get a specific movie
query on /movies/movie-id
Get all actors playing in a specific movie
query on /movies/movie-id/actors/
Get all movies a specific actor has played in
query on /actors/actor-id/movies/
The optional query selection statement can be used to filter the result. To get movies from the last 10 years a specific actor has played in, you would add the selection movies_year>=2005 to the last query.
By using a contract like this you wouldn't expose the junction table, instead you provide a REST-like interface to your database.
The job of the ContentProvider is to map these operations onto the database or any other back-end.

Categories

Resources