I just started using Room library for database and I figured out that it is more complicated to put an object in the table. I made a diagram to demonstrate the situation in my app:
I could insert the Workout object into my table, but I have to create Converters to simplify the Exercise List object.
I also would like to create a table for Exercises that have the Workline List objects..
Any suggestions?
Thanks in advance.
Related
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.
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.
I'm making an application with a database of courses (of school) that the user is participating in. I want to display those courses in a list (im using listview) and use also the subitem (extra information of that course) of the listitems. I found a tutorial (http://www.softwarepassion.com/android-series-custom-listview-items-and-adapters/) that displays a list like I want but it uses a class to store the data in instead of a database. So the tutorial uses an arraylist of objects of that class. It would be a detour though if i had to put my information from my database into a class to put it in the list.
Does anyone have a clue how to solve this?
Thanks!
I found a beter way. By using a simple adapter and putting the values of the cursor in a hashmap in a arraylist. Found the idea from this site: http://eureka.ykyuen.info/2010/01/03/android-simple-listview-using-simpleadapter/
Here is a perfect tutorial for what you need. It shows you how to create a simple SQLite database and then populate a listview using the database.
SQLite Database creation and Listview Population Tutorial
I have following scenario. There is OrderHeader and OrderDetail tables in SQLLite database. I have Activity where I want to display that data. There is number of fields...
The way I see it - it has to be like this:
Get data from my content provider (I have it).
Get ordinals for columns in cursor.
Get values from cursor and format/assign them
Like I said - there is MANY fields and writing this kind of code (especially #1 and #2) very tedious and boring :)
So, I've got this idea.. Since my data comes in as JSON to begin with (from web) - I can store original JSON presentation in database along with parsed-out data and when I need to bind - all I need is to query table for this column and deserialize with GSON. This way - #1 and #2 will be 3 lines instead of many. And I will work with POJO...
Does that sounds good or there is natural nice way to bind views to data from database?
Use a ListView and a SimpleCursorAdapter (or extend it).
Here's the situation. I have a bunch of objects that implement Serializable that I want to store in a SQL database. I have two questions
Is there a way to serialize the object directly into the database
Is that the best way to do it or should I
Write the object out to a formatting String and put it in the database that way and then parse it back out
Write each member to the database with a field that is unique to each object
Its generally not a good idea to try and put any sort of object (serialized/deliminated) in your SQL because modifying them is always a bitch.
It sounds like you're on the right track with idea 2. Is this a one-to-many situation? (because then a xref would obviously be the right answer) or even a foreign key would be better. cheers.
I'd still have a table per class + simplistic DAO.
If you absolutely want to do it wrong :), then serialize to JSON and persist the resulting string.
You could store the objects directly using db4o:
http://www.db4o.com/Android/default.aspx