Atomically update multiple related tables - android

I am working with SQLite in Android. I have a model object that contains three lists, one of which is a list of lists. So I have five tables: A for the object, B for the list of lists, C for its lists, and D and E for the other two lists. The case that has me stumped is if the user is updating an existing object, and may or may not have made any changes to its lists. I think I will have to query each table B through E for records whose foreign keys match the primary key of the record I'm updating, and then loop through those results to see if I have a matching item in the lists, manually deleting/inserting/updating as necessary. But it seems to me like there should be a better way?
Related questions: If I wrap this whole operation in beginTransaction() and setTransactionSuccessful(), do I need to do anything else to ensure atomicity? I have never dealt directly with locks in my databases, do I need to add error checking to my existing queries to handle an event in which they are blocked? Is there any error case in which I would need to manually cancel the transaction, or will that occur automatically when I close my database connection?

Have a look on SQLite triggers here, This is exactly what you need.
If any error has occurred somewhere after beginTransaction(), then try to catch an exception and do not mark this transaction as successful. Without
setTransactionSuccessful() call your data wont be affected.

Related

How to retrieve random children from Firebase

Suppose we would like to retrieve 15 random children from questions node having this database structured as below:
1. The first (intuitive and discussed) way of retrieving random children from Firebase is to retrieve the whole required parent node (questions as dataSnapshot) and then select some random children on the client-side. This method has been pointed out in many posts, like in this one here .
Obviously, this method has its downsides; for example when querying through a large sized parent node (e.g. over 10.000 children) retrieving such an amount every time would result in a huge bandwidth usage as well as a client side burden. (when we actually require only a small amount of children)
2. Moving on: another approach, as described here which uses an iterator somehow bypasses the whole client side burden, yet the huge bandwidth usage could still occur as we download the whole parent node every time.
3. An interesting approach is described in Tom's answer in this firebase discussion which proposes:
A hacky way of doing this would be to generate a random key and do a query with startAt().limit(1). I have a feeling this could hurt the performance of your firebase though, so this should not be an operation you perform often. We don't have a real random sample function.
This solution actually sounds pretty good, yet I am not sure how it would indeed impact my Firebase.
4. Another silly solution could actually be naming the question ids manually, so to speak, from 0 to N, therefore handling the random group of ids on the client side and retrieving the questions spot-on by knowing the actual name of nodes.
5. And lastly, I have come up with the following solution to which I ask if is more or less viable than the ones presented above: creating another parent containing the question ids only and when needed, one should retrieve this parent which is much "lighter" than questions parent . From there, I would have the specific random ids and I would only need to snipe for those children. To better understand my meaning, please check the below picture:
Now, from this method arises the following issue: is assigning (let's say) 15 eventListeners good practice? Could this actually slow up things? (Note: this applies to methods 3 and 4 as well)
And ultimately, which method is actually the optimal one when querying from a large database for some random children?
You can use the classic solution as I explained in this answer but if you are afraid of getting huge amount of data then use instead 15 listeners. There is nothing wrong in using listeners as long as you remove them according to the life-cycle of your activity. So, IMHO go ahead with 15 listeners.
We have 2 case here
case 1
If you want to grab all details of the random ids at once, then I suggest 1 listener to the parent node (get value of datasnapshot using pojo class).
case 2
If you want to get the details independently upon request then you will have to attach a listener to each (random id) that you want.
Concerning performance
Try to use only Listener For Single Value Events as they listen one time and then stop (better for performance).
Dont use Value Event Listener (because these listeners keep checking for changes and therefore bad performance as listeners increase).
EDIT
lets say you listened to (questions_ids) node, now you have access to the random id keys, store them in a String variable, and then inside the same listener add another listener to (questions) pointing to the id that you want to grab details
//first listen to question ids ref (the one with 15 ids)
question_ids_ref.addListenerForSingleValueEvent(...{
//grab the key of each (random id) and store in variable
String random_01=......;
//run another listener this time to questions ref
questions_ref.child(random_01).addListenerForSingleValueEvent(..{
//get details of random_01 and so on....
});
});

How to transfer RealmResults accross threads

I'm using a recycler view in my app and would like to do some computation on a background thread, obtain a list of RealmObjects, and refresh my adapter to it.
As a bit of background, I have a non trivial sorting requirement, and the recycler view needs to display objects that result from queries on different tables(though they still produce the same object type). I don't want to do these potentially expensive queries on the main thread.
What is the best way to do this? AFAIK, I can
Get a list of ids(String) from the background thread, and do a query on the main thread. So I would do something like realm.where(ObjectA.class).in(listOfIds).findAll(). However, I don't think I have a guarantee that the order of the collection is the order of my listOfIds, which i have sorted in the background. I could then sort the realm collection manually.
Or, I can do a realm.copyFromRealm(listOfObjectA), assuming I have gotten a list of objects from my background thread. With this way it feels cleaner to me but i obviously lose the auto-refreshing functionality, not to mention that it will be memory-intensive. It seems that the expensive copying would take place on the main thread, which would undermine my efforts to move things into the background thread.
I was hoping there was a method that would allow me to transfer RealmResults or RealmList from one thread to the other. Does anyone have recommendations on how to do this?
findAllSortedAsync
I have a non trivial sorting requirement
If this sorting is based purely on your RealmObject fields, you can use RealmQuery.findAllSortedAsync(...) method, which will execute the query and sorting for you on a separate worker thread. This is the best option. If it's possible, you can also do sorting in two stages, one using findAllSortedAsync and second one on main thread on already obtained objects - possibly the second stage would not be as costly if the results are pre-sorted by realm.
and the recycler view needs to display objects that result from queries on different tables
You can look for a possibility to create a linking between these objects, for example if RealmObject A has a field b, you can sort A by fields of b also - this could fix your problem, and keep everything in one realm query.
Requery with sorted IDs (NO)
Get a list of ids(String) from the background thread, and do a query on the main thread...
You're right - there is no guarantee of the results being returned in the original ID list order, so this is not really an option.
copyFromRealm
Or, I can do a realm.copyFromRealm(listOfObjectA)...
That is correct, however you have to be aware of the limitiations and memory overhead using this method, namely:
you get a snapshot of the data and have to manually update the recycler with new snapshots
single change to an object conforming to your original query will trigger an update and, possibly, sorting all over again
It seems that the expensive copying would take place on the main thread, which would undermine my efforts to move things into the background thread.
Not really, if you perform copyFromRealm on thread A and pass the list to thread B, the hard copying of the values from realm will be executed by thread A, so it's fine.
You can not move "live" RealmObjects across threads, so the two options you've laid out are pretty much what you're left with.
If you do your query on the background thread and use copyFromRealm to create disconnected objects, sort them, and then pass those back to the main thread, that will all happen on the background thread, so you're fine there.
(Small note: if you display the data in a different format than it is in Realm, you could also map it to a class that's quicker to then populate your views from instead of using the Realm object in the UI, since you lost the sync features anyway.)
Otherwise, if you need them to be connected to Realm, I think you will have to do the ID list transfer and suffer the cost of sorting them on the main thread.
Use copyFromRealm method
In java:
MyRealmObject unManagedRealmObject= realmInstance.copyFromRealm(myRealmObject);
Well in kotlin, we can do it in a more better way:
var nonRealmObject: MyRealmObject?=null
set(value) { // here value is child of RealmObject
if (value!=null)
field = realmInstance.copyFromRealm(value) // converting RealmObject to unmanaged realm object
else
field=null
}
Now when you assign:
nonRealmObject = someRealmObject // set(value) method will be called and it will convert realm to unmanaged realm object
Note: realmInstance is an instance of Realm already created, if you create new reference make sure to close it when your work is done.

SimpleDB - how long after insert until item is available to be read?

I have a Fragment, and once the user presses OK, an Item is added to my database and its ID is added to the ArrayAdapter. Immediately after, the adapter tries to draw the view, but the first time it tries to get its attributes, it returns a null HashMap (it gets drawn properly the following times).
Is there a way to make sure the item is in the table before trying to get its attributes?
Even putting the attribute retrieval into a while loop until it returns a not-null HashMap doesn't work so it doesn't look to be an issue of time.
You need to do Select or GetAttributes with ConsistentRead=true as Amazon SimpleDB supports two read consistency options: eventually consistent read and consistent read. Eventually consistent read is default. For more detail please refer doc. link
Try using AsynTask.
Add item to database in doInBackground.
Read it in postExecute.
You are done.

Using multiple methods in a transaction

I'm making an Android app, which gets its information from XML files.
I'm filling the information in a database, for easier acces during the program's runtime, thanks to the power of queries.
However it came to my attention, that using Transactions greatly improves speed, so naturally, I want to use that.
My problem is the following tho;
In the idea of abstraction, after parsing all the information of one subject, the information gets send to the correct entity (class), and inside that entity there is a method that will add it in the database. After that, it returns to the parser which continues to read the next subject, which in it's turn will be send to right (and probably different) class again.
This is implemented with a switch statement, with every case pointing to a different class constructor.
If I want to use the speed of transactions, I would need to start a transaction already before the parsing, run through the parsing and query building (as far as I understand, all queries build within the transaction, are collected and in the end all executed as a bunch) and then end the transaction, once the whole file is parsed.
To make this a bit clearer, or faster to read; The code idea would be;
Class parser(){
database.beginTransaction();
try{
// start parsing in a whole different class, which also points to SQL queries (in different classes again) in the entitys with a switch
}catch(Exception e){
database.endTransaction();
}
database.endTransaction();
}
I hope i formulated my question clearly enough.
Kind regards,
Yes, you've got the general idea. However, you need to be careful to mark the transaction as successful when you finish parsing, and also to ensure the transaction is always closed even in the event of an exception.
Example from the docs:
db.beginTransaction();
try {
// do all the parsing in here
...
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}

Android AsyncTask - One SubClass Per Database Operation?

I have an activity for initialising a game, that does multiple selects and inserts from a number of SQLite tables.
I'm trying to understand AsyncTask, but, from all the examples I've read so far, I'm wondering if I am going to have to subclass AsyncTask for every single different data operation I need to do?
For example, my NewGame Activity does the following:
1) Insert new player record into PLAYER table
2) Insert new player's pet record into PET table
3) Select cursor of n records from INVENTORY
4) Insert array of ranomly chosen inventory items into PLAYER_OWNED table
5) ....more things of a similar nature
There are going to be a few more selects and inserts for various things too, so having an individual subclass for each one is going to get crazy. Not to mention that there will be about 8 activities for this game, all relying heavily on database reads and writes.
So, basically, how do I best use AsyncTask to carry out a number of different SQLite operations?
You can pass parameters to a AsyncTask, even more, if you use nested clases, you can use global variables from inside the AsyncTask class, by using one of the above or both mentioned aids you should be able to use the same class and have it do diferent things depending on the parameter you pass. I see no real need to define multiple AsyncTasks.
You will need to define a AsyncTask in every activity.
I wrote need, because you really dont have to, but its comfortable to do it this way, and its easy to read/write code, as the AsyncTask is asociated to the activity only. This is of course suposing you use nested clases, I see no point in writing a separate class file just for an AsyncTask.

Categories

Resources