greenDAO update and updateInTx not working - android

I'm using greenDAO 3.1 for one of my projects. Since I needed my id to be UUID I've decided to store it as ByteArray. Now the problem is I can't update my entities using update or updateInTx method and I have to use insertOrReplace or insertOrReplaceInTx method.
Can anybody tell me what is going on and why can't I update using update methods?
Is there any downside to using insertOrReplace methods instead of update methods?
This is my Entity's schema code:
Entity book = schema.addEntity("Book");
book.addByteArrayProperty("id").columnName("_id").primaryKey();
book.addStringProperty("title");
book.addByteProperty("edition");
book.addStringProperty("authors");
book.addStringProperty("desc");
book.addStringProperty("pic");
And here's my update code:
BookDao bookDao = daoSession.getBookDao();
List<Book> books = bookDao.loadAll();
for (Book book : books)
book.setDesc("It doesn't really matter!");
bookDao.updateInTx(books); //This isn't working

After a lot of searching and trouble I found the reason.
Since you can't query BLOB type in sqlite and since update methods use a condition over id in WHERE clause, the update method won't find the record I'm looking for. On the other hand when I use one of insertOrReplace methods, since the id field is unique it can't insert redundant id to the table and it completely replaces the old record with the one I'm trying to update. So, there was no problem with update methods, the real problem is with using ByteArray as id.
For the same reason, I also encountered an error when selecting using load method.

Related

Maintaining a count field in a table using Room and Java on Android - looking for advice

I am using Room on Android and programming in Java and am finding myself jumping through hoops to maintain a count field in a table due to some of the callbacks and background thread requirements and I was hoping somebody might have a simple solution.
I am doing an insert into a table for logging purposes. For each ScenarioRun I need to maintain a count. So it is not the count of records in the whole table, just for a given ScenarioRun.
I believe the best place to do this is in the ViewModel when I am inserting the RunLog entry. Ideally I would calculate the count from the Log table using the RunId, so my Dao would have this query in it:
#Query("SELECT COUNT(*) from ScenaroRunLog WHERE scenarioRunId=:scenarioRunId")
int getScenarioRunLogCount(int scenarioRunId);
Which I would pass through my repository to my ViewModel so on an insert, I would increment it:
public void insert(ScenarioRunLog scenarioRunLog) {
// code to set the count in the object something like:
// int count = scenarioRunLogRepository.getScenarioRunLogCount(scenarioRunLog.getScenarioRunId);
// scenarioRunLog.setCount(count);
scenarioRunLogRepository.insert(scenarioRunLogId, scenarioRunLog);
}
I could do it in the repository but the only way I can see how to do this is by using allowMainThreadQueries(), which doesn't seem like a best practice or using Executors. Basically the suggestions here.
Is there a better way to do things in this case? I have also found simple things to be challenging.
I could also simply load the ScenarioRun in the ViewModel and reset the count at that time, maintaining it in the ViewModel from that point on, but I have the additional challenge of loading the ScenarioRun. I guess I could do this with another AsyncTask for the select, like they do here.
LiveData for RecyclerViews and other UI components are great, but simple queries have seemed to be challenging. Even returning RowId's on inserts has required a lot of work. Looking for some guidance here. I appreciate the help in advance.

Injecting entity object while calling google cloud endpoint from android

How do I pass the arraylist to google cloud endpoint? It doesn't seem to work.
Edit start ----
Here is the signature of the endpoint with arraylist as input
public CollectionResponse<String> listDevices(#Named("devices") ArrayList<String> devices)
However when I iterate over this arraylist, I get all the records condensed into one. So even though I pass 10 strings, I get only one in my endpoint.
Edit end ----
I read somewhere that I should create a wrapper entity for arraylist and then pass it.
Edit start ----
So I created the entity containing the arraylist
#Entity
public class DEviceList {
ArrayList<String> devices;
}
and modified the signature as -
public CollectionResponse<String> listDevices(DeviceList devices)
Is it possible to pass object of DeviceList from client even though it not #Named? Can you provide the syntax?
My understanding is that since it's an entity it cannot be #Named, so while calling I need to inject it.
But google allows only three injected types -
1. com.google.appengine.api.users.User
2. javax.servlet.http.HttpServletRequest
3. javax.servlet.ServletContext
So above signature would not work.
So I changed the signature to -
public CollectionResponse<String> listDevices(HttpServletRequest request)
and inside I could get the entity as
DeviceList deviceList = (DeviceList)request.getAttribute("deviceList");
However I am not sure how to call this endpoint from the android client?
How I do pass the entity object using HTTPServletRequest?
Edit end ----
How do I do that? Can anyone cite an example?
The way you word your question, it seems the call is silently failing. That can't be. You must be receiving some kind of exception or log somewhere which could help you identify your issue better. You could read this article to refresh on cloud endpoint APIs and android.
If you are having trouble passing an arraylist of objects from your client to the API, I would suggest checking some things:
does the argument type in the API match what is being sent from the client? Do they both have access to the class definition?
if the data type inside the arraylist is a primitive, and it still fails, perhaps the advice you read "somewhere" was referring to the need (although I don't think this is the case) to use a wrapper object which simply contains one field - the arraylist, and pass that along the line?
If either the reminder to check your logs/error messages or any other info in this answer helped you resolve the issue, please remember to accept it, but not without first editing your post to explain how you resolved your issue.

android greendao update only specific fields in entity

i have been searching for a while for a solution to my problem without success.
I have an application in which I receive information for a particular entity in my database from different services, so I am using greenDAOs insertOrReplace methods so whenever the entity already exists in my DB it gets updated instead of recreated.
So far so good.
The problem is.. let's say for example sake my entity is called User, with fields id, title, and displayName.
So in the first call I get a JSON object containing a user with only its id and title fields, so I insert it into the DB and naturally the displayName gets inserted as NULL.
Afterwards from another service I get another JSON containing the same user (same id field), but it comes with the displayName as well, but doesn't include the title info at all.
So whenever I run the insertOrReplace on the DAO object automatically generated by greenDAO, the user gets updated but as the title info was not present, when it gets updated the title field gets reset to NULL, so I end up losing data.
Unfortunately I am unable to change the data being returned from the services, and haven't been able to fix this issue. I find it hard to believe there is no easy way to tell the DAO object to update only certain fields and no all of them.
I was looking at the code generated by greenDAO and in the dao objects generated there is a bindValues method which gets called before the query gets executed, and apparently it filters out the NULL properties from the object, but either way it gets updated with the NULL value.
I was able to come up with some sort of fix by modifying the final dao object being generated by adding some methods from the parent class, but I don't think this is a good solution because I would have to do this for all the dao objects. (I know it's possible to define a custom superclass but this only applies for the entity object and not the DAO one).
I would really appreciate if someone has any idea on how I could resolve this, and sorry for the long explanation, I just wanted to be clear on my issue.
Thanks.
First of all: I wouldn't tamper with the generated code unless you really know what you are doing. Modifications may have effects on caches and data-integrity.
Generally you are following this (insert-or)-update-approach if you are using a ORM-Framework (like greendao):
Try to get the entity, that you want to modify from the db (maybe it is already in cache, so this may not be a real database operation)
If you don't have such an entity: create it
Modify the entity according to your needs
Insert or Update it in database (in greendao you would use insertOrReplace)

greenDAO and data validation

I'm looking into using greenDAO for my Android app, but I noticed it doesn't seem to support any kind of data validation other than "not null", "unique", and foreign keys, either on the SQL level (constraints defined when creating tables) or the Java level (validation logic in setter methods). "Keep sections" don't seem like they would be helpful in this case because you can't have them within individual methods. Am I missing something, or would I really need to add yet another layer on top of the generated Java objects if I wanted to validate input data? (I'm somewhat confused how the framework could be useful without providing any place to include validation logic.)
1.
You can write a method
boolean check ();
in KEEP-SECTION of the entity which you call manually before INSERT or UPDATE.
2.
Another possibility is to extend the sourcecode of greendao generator to support checks: In property.java you could add a method to Property.Builder
public Property.Builder check (String expr) {
property.checkConditon = expr;
}
Of course you would have to introduce the String checkCondition = ""; and use it for generating the dao in the dao-template.
Problem:
With new versions of greendao your changes would be lost (but then again new version may already contain such a feature)
3.
A third possibility is to copy the generated CREATE TABLE statement, modify it to fit your needs and call your modified statement instead of the original one or to drop the original table and call your statement.
Problem:
If your table changes you will have to repeat this.

Adding two relations via ParseRelation always sets the first class as target class

I am having a weird issue here.
The class Points I want to save data into, has two columns race and challenge which are relations to other classes with the same name.
I have asked this question on Parse.com forums as well
On the client side on Android, if I add the relation via pointsObject.put("race", raceObject), it throws an error saying that the type of "race" is Relation and I am providing a *Pointer
The iOS Counterpart of the app I am working on is completely able to save relations nicely - Happily Coded about 2 hours ago
When I use ParseRelation to add a one-to-many relationship, it takes only the first class as target class.
This code should explain:
ParseRelation<ParseObject> initiatorChallengeRelation = initiatorPoints.getRelation("Points");
initiatorChallengeRelation.add(challenge);
initiatorPoints.put("challenge", initiatorChallengeRelation);
ParseRelation<ParseObject> initiatorRaceRelation = initiatorPoints.getRelation("Points");
initiatorRaceRelation.add(race);
initiatorPoints.put("race", initiatorRaceRelation);
The first block of code sets the target class for the relation as "Challenge".
The second block tries to set the target class of the new ParseRelation object to "Race", but initiatorRaceRelation.add(race) is where it fails and throws an error : "IllegalArgumentException: Related object object must be of class Challenge, but Race was passed in."
I used Eclipse Debugger to check the data in the both Relation objects and found the thing about target classes being the same
Any help on where I might be going wrong?
I have been dealing with this issue since more than 12 hours and its really become a roadblock for me.
Any help would be deeply appreciated
Is Points a relation? From what you have mentioned, it seems so.
Assuming that initiatorPoints is a Points Object, you should get the challenge relation using
ParseRelation<ParseObject> initiatorChallengeRelation = initiatorPoints.getRelation("challenge"); //for challenge
then
initiatorChallengeRelation.add(challenge);
Similarly, for race
ParseRelation<ParseObject> initiatorRaceRelation = initiatorPoints.getRelation("race"); //for race
initiatorRaceRelation.add(race);
I think you need not even use initiatorPoints.put("challenge", initiatorChallengeRelation);
Once, you say
initiatorPoints.saveInBackground(callback), Parse updates the changes in the object by itself.
But do not forget to save the object once you have added the relation data. Hope this helps!

Categories

Resources