How to make sure saving ParseObject and ParseRelation using saveEventually() - android

I have started using Parse library recently for Android app. I want to store user contacts using saveEventually and then use the ParseRelation to relate the same to user. As there are multiple contacts mapped to user, I am using below code to handle my save functionality.
ParseRelation relation = ParseUser.getCurrentUser().getRelation(relationshipName);
for(int entityIndex = 0; entityIndex < entities.length;entityIndex++) {
...
entity[entityIndex].saveEventually(); relation.add(entity[entityIndex]);
...
}
ParseUser.getCurrentUser().saveEventually();
Here I am using saveEventually() for each valid entity (ParseObject) and then adding the same to relation. Later once all the objects are added to ParseRelation, at the end I am calling saveEventually() for ParseUser to store all the relationship to Parse.
Is this approach right? I am getting below exception at relation.add(entity[entityIndex]);
All objects in a relation must have object ids.
It seems this suggest some network connectivity issue and ParseRelation is not getting unique objectId for each ParseObject, but I was assuming that this saveEventuall() will handle this scenario well with ParseRelation
Kindly suggest. I am using Parse library version 1.1.11
Thanks.

Any object that's added to a ParseRelation must be saved first. The saveEventually call is non-blocking, so it's unlikely that the object will already have been saved by the time execution reaches the very next line when it's added to a ParseRelation.
Since you need to make sure the object is saved first, you should use saveInBackground instead of saveEventually. Then make sure to add the saved object to the relation from inside saveInBackground's SaveCallback. This will ensure that the object has been saved before being added to the relation.

Related

firebase persist data with circular reference

I've a simple data that i want to persist on firebase.
This data is a domain class for my relational model (i started with a relational model and now im deciding whenever or not migrate to firebase, but for awhile im working with both... or trying to)
To persist a new instance if my class on firebase i need to do:
Map<String, Object> firebase = new HashMap<String, Object>();
firebase.put("raffleDate", this.giveaway.getRaffleDate());
firebase.put("thumbnailUrl", this.giveaway.getThumbnailUrl());
firebase.put("mustFollowList", this.giveaway.getMustFollowList());
firebase.put("owner", this.giveaway.getOwner());
firebase.put("amountFriendsToIndicate", this.giveaway.getAmountFriendsToIndicate());
firebase.put("mediaId", this.giveaway.getMediaId());
((App) getApplication()).getFirebase().child("giveaways").child(this.giveaway.getMediaId()).setValue(firebase);
because besides these fields Giveaway has one last other field which has a circular reference to itself
#ToMany(referencedJoinProperty = "raffle")
#Expose(deserialize = false, serialize = false)
private List<UserOnGiveaway> attendantsTickets;
This field maps the relatioship between user and its giveaways, UserOnGiveaway class has a reference to User and Giveaway so when i try to persist i get a very long non compreensive error that I can just guess is due some stackoverflow because of the circular reference
The thing is I DONT REALLY CARE ABOUT PERSISTING THIS FIELD, in my actual "hybrid" archtecture i'm using firebase only to persist data shared among users, individual user data is being stored locally on android sqlite
So i would like to know is there any way i can annotate this field to force firebase ignore it?
or is there any parameter is can set on firebase call to do it?
PLEASE do not suggest transient as it will also affect my ORM
PLEASE2 do not suggest changes on domain since i'm giving a try to firebase i wont make any structural changes before decide for it.
thanks
You can use the #Exclude annotation on a field or getter/setter method to omit it from serialization with the Firebase SDK.

Merge additional nodes to Stripe token before passing it to the Firebase database

I want to be able to add an additional node to my token object after receiving it from Stripe to push it to the firebase database in a single write. In my project, I am pushing the token object to the database and then calling another write to add the additional node...
DatabaseReference tokenRef;
tokenRef = mRootRef.child("users").child(mUser.getUid()).child("payments").push();
tokenRef.setValue(token);
tokenRef.child("amount").setValue(500);
Ultimately, I want my database to look like this on a single write
Is there a way to merge the "amount" node to the token before passing it to firebase database?
You will have to create a Map of all the key/values you want update at once and pass that Map to setValue for a single update. This means you'll have to pull all the individual values out of token.
Alternatively, you can define a new property of token that contains the amount, and set it in there. Or, if you can't modify whatever the class is for token, you can define a new class that contains all the data from token, and add amount to it, populate an instance of that class with all your data, and pass that to setValue().

Firebase Realtime Database add to list in MutableData

How can I add to a list in a Firebase Realtime Database transaction using MutableData?
In a normal non-transaction type update, I can simply use
DatabaseReference refDatabase = ...
refDatabase.push().setValue(value);
But with MutableData, no such push() method exists. How to add to a list and get a unique key?
I'm looking for something like
public Transaction.Result doTransaction(MutableData mutableData) {
mutableData.push().setValue(value);
...
but this does not exist.
I think I understand the point of your question and comment: It would be nice to know if the absence of push() was an oversight by the API designers, or it was intentionally omitted to prevent users from doing something that was unsafe or otherwise "bad".
There is a workaround, right? You know the reference the transaction is run on. The mutable data is the value of that reference location. Can't you just make the reference variable a package field, or a final class variable, and use it in the callback to call push()? It's ugly, but I think should work.
I'll also take a guess that push() was omitted from MutableData for a reason. The documentation for doTransaction() states:
This method will be called, possibly multiple times, with the current
data at this location. It is responsible for inspecting that data and
returning a Transaction.Result specifying either the desired new data
at the location or that the transaction should be aborted.
Since this method may be called repeatedly for the same transaction,
be extremely careful of any side effects that may be triggered by this
method.
Maybe generating keys and adding elements to a list is not something you want to be doing, since it may occur multiple times.

Android: how to keep realmlist updated in the UI

I have a recyclerview which shows a list of students.
All of the students are held in a realmlist in the adapter.
When the user can ask for a data refresh, than the server sends the list of students back to the user.
What i am doing now is to download all of the information from the server , store it in the db , than retrieving it from the database(via realmresults) and than converting the realmresult to realmlist.
My question is how to properly update the UI?
I have seen in the documentation that realmlist have a managed mode where they are updating the ui automatically..
What is this managed mode? What does it means?
How do i use the realmlist to keep it in a managed state?
And what is the right way(aka best practice) to use realmlists?
Note that i cannot hold my information as realmresult directly because im performing some manipulation on the data that i dont want it to be saved.
Managed Object vs. Standalone
The standalone RealmObject/RealmList is created through the Object's constructor or the Realm.copyFromRealm() method. The data accessing in the standalone object won't go through the underline storage engine, instead, it behaves just like normal object. So the standalone object won't be refreshed when data changes. Examples for standalone object:
MyModel myModel = new MyModel(); // Standalone
MyModel model = realm.where(MyModel.class).findFirst(); // This is managed object.
MyModel standaloneModel = realm.copyFromRealm(model); // The returned value is standalone object.
MyList myList = new MyList(); // Standalone
The managed RealmObject/RealmList are accessing data though Realm's underlying storage engine. They are created when you do query from Realm, or the return from the copyToRealm() (and its variant methods). Like:
MyModel model = realm.where(MyModel.class).findFirst();
MyModel model = new MyModel(); // This is a standalone object.
model = realm.copyToRealm(modle); // The returned value is managed by Realm now.
MyList myList = realm.where(MyModel.class).findFirst().getMyList();
How to properly update the UI
The suggestion is using Realm's change listeners. See https://realm.io/docs/java/latest/#notifications
And what is the right way(aka best practice) to use RealmList?
This is a bit confusing, but Realm is introducing RealmCollection into the next major release (v0.89.0). See https://github.com/realm/realm-java/pull/2345.
Note that i cannot hold my information as realmresult directly because im performing some manipulation on the data that i dont want it to be saved.
If the RealmList is in managed mode, the data changes will be saved as well. If you don't want some data to be saved, you could consider to use #Ignore annotation on those fields. See https://realm.io/docs/java/latest/#ignoring-properties
Update on 04072016
RealmList vs. RealmResults:
RealmList is a list of RealmObject saved as a field of a RealmObject. It represents the one-to-many relationship in Realm.
RealmResults is the results of query.
Both of them (if RealmList in managed-mode) will be auto-refreshed when data changes.
You can get a RealmResults from a RealmList by RealmList.where() like:
RealmResults results = myRealmList.where().findAll();
This answer will be a bit out-of-date after Realm v0.89.0 released, because of new RealmCollection.

Parse: How to prevent pointers from being saved recursively in Android?

I a parse class called Booking which has pointers to Parse classes: Ticketand _User and other irrelevant fields.
Where Ticket has pointers to Location and more irrelevant fields.
Most classes other than the Booking class has Class level Access List Restrictions, which is necessary for the security of my app.
The following is the code I use to attempt to save a booking object using the android SDK:
final Booking booking = new Booking();
// For pointer like behaviour
Ticket ticketPointer = Ticket.createWithoutData(Ticket.class, bookingData.getTicket().getObjectId());
booking.setTicket(ticketPointer);
ArrayList<Coupon> couponPointers = new ArrayList<>();
for (Coupon coupon : bookingData.getCoupons()) {
// For pointer like behaviour
couponPointers.add(Coupon.createWithoutData(Coupon.class, coupon.getObjectId()));
}
booking.setCoupons(couponPointers);
booking.setClient(ParseUser.getCurrentUser());
booking.setTicketCount(bookingData.getTicketCount());
booking.setPaymentMethod(Booking.PaymentMethod.CASH_ON_ARRIVAL);
booking.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (asserter.assertPointerQuietly(e)) {
e.printStackTrace();
} else {
l.d("Successfully posted a booking request on server");
}
}
});
The problem is that parse saves object recursively, so even objects pointed to by the pointers are saved along with the object being saved. And since the other classes can't be accessed by regular users, exceptions are raised when attempts to save these objects pointed to by the pointers are made. So, I put the ticket and coupon objects into the booking object in the form of pointers using the createWithoutData method as marked in comments as // For pointer like behaviour as per the solution to saving pointers here.
All this works well, and I got rid of exceptions raised by accessing the Ticket and the Coupon class which were saved recursively.
However, to my surprise, the above code results in another exception caused by an attempt to access the Location class which is pointed to by the pointer of the Ticket object which is pointed to by the Booking object(2nd level pointer)!!!.
Is there any way to prevent the location object from being pointed to? An ideal solution would be to disable recursive saves in the first place, but any solution would be appreciated.
A workarounds exist, but it is ugly, and I would like to avoid it: It involves using a string representation of the object id of the object instead of the pointer.

Categories

Resources