I have 3 tables:
#DatabaseTable(tableName="user")
public class TableUser implements Serializable{
#DatabaseField(dataType = DataType.SERIALIZABLE)
private LinkedList<TableProfile> profiles;
}
#DatabaseTable(tableName="profile")
public class TableProfile implements Serializable{
#DatabaseField(dataType = DataType.SERIALIZABLE)
private LinkedList<TableRevel> revelations;
}
#DatabaseTable(tableName="revel")
public class TableRevel implements Serializable{
private String our_profile_id;
#DatabaseField(canBeNull=false)
private String other_profile_id;
#DatabaseField(canBeNull=false)
private String info;
#DatabaseField(canBeNull=false)
}
I need update fileds in "revel" table , I get revelations from Json without object "user:{profile:...}"
I think I need use QueryBuilder, please write short example of this query if its passible.
I would force the column name to be something static so you can search on it. Something like this:
#DatabaseTable(tableName="revel")
public class TableRevel implements Serializable{
public static final String PROFILE_ID = 'id';
#DatabaseField(canBeNull=false, columnName = PROFILE_ID)
private String our_profile_id;
#DatabaseField(canBeNull=false)
private String other_profile_id;
#DatabaseField(canBeNull=false)
private String info;
}
Then I would do something like this to do the update:
public class foo extends OrmLiteSqliteOpenHelper {
...
public updateField(String jsonString) throws SQLException{
Dao<TableRevel, String> revelDAO = getDao(TableRevel.class);
QueryBuilder<TableRevel, String> queryBuilder = revelDAO.queryBuilder();
queryBuilder.where().eq(TableRevel.PROFILE_ID, getIdFromJson(jsonString) );
PreparedQuery<TableRevel> preparedQuery = queryBuilder.prepare();
TableRevel revelEntry = revelDAO.queryForFirst();
//update the entry here
...
revelDAO.update(revelEntry); //update the data
I have written a project that uses OrmLite. The link to the class that does a lot of the sql stuff is here: https://github.com/kopysoft/Chronos/blob/development/ChronosApp/src/com/kopysoft/chronos/content/Chronos.java
Hope this helps!
As I understand Ethan's answer it would mean loading the TableRevel object into memory in order to update it. Depending on the type of update you need, this might be a viable alternative:
public update(String jsonString) throws SQLException{
Dao<TableRevel, String> dao= getDao(TableRevel.class);
UpdateBuilder<TableRevel, String> updateBuilder = dao.updateBuilder();
//Update the columns you want to update for the given jsonString-match
updateBuilder.updateColumnValue(TableRevel.My_FIELD, newValue);
// ...where the json string matches
updateBuilder.where().eq(TableRevel.PROFILE_ID, getIdFromJson(jsonString));
//Execute the update
dao.update(updateBuilder.prepare());
}
Sorry if I misunderstood your question, but the info you provide is a bit sparse and I for once have no idea about the internals of json ;) . - either way this update query might suit your needs, depending on how complex your udpate is. Big plus: No need to load the object into memory.
Related
I have this query set up to return all the records from these tables and display the information on a recyclerview in android. the DB is set up using the Room persistence library aka SQLITE.
#Query
("SELECT moodBeforetable.userId,
moodBeforetable.moodBefore,
moodBeforetable.cbtId,
cbtTable.automaticThought,
cbtTable.twistedThinkingPK,
cbtTable.challengeThought,
cbtTable.rationalThought,
cbtTable.date,
moodAfterTable.moodAfter,
twistedThinkingTable.twistedThinkingPK,
twistedThinkingTable.allOrNothing,
twistedThinkingTable.blamingOthers,
twistedThinkingTable.catastrophizing,
twistedThinkingTable.emotionalReasoning,
twistedThinkingTable.fortuneTelling,
twistedThinkingTable.labelling,
twistedThinkingTable.magnifyingTheNegative,
twistedThinkingTable.mindReading,
twistedThinkingTable.minimisingThePositive,
twistedThinkingTable.overGeneralisation,
twistedThinkingTable.selfBlaming,
twistedThinkingTable.shouldStatement
FROM moodBeforetable
JOIN cbtTable ON moodBeforetable.cbtId = cbtTable.cbtId
JOIN twistedThinkingTable ON cbtTable.cbtId = twistedThinkingTable.cbtId
JOIN moodAfterTable ON moodAfterTable.cbtId = cbtTable.cbtId
WHERE moodBeforetable.date >= datetime('now', '-1 year')
AND moodBeforetable.userId = :userId
ORDER BY :date DESC")
LiveData<List<MoodBeforeTable>> moodLogsAll (int userId, String date);
When I try to compile the app I get the following error:
The query returns some columns which are not used by com.example.feelingfit.persistence.tables.MoodBeforeTable.
You can use #ColumnInfo annotation on the fields to specify the mapping.
Could anyone help me debug this and find out why the app wont compile?
Problem is Room cannot map the result from your custom query to existing MoodBeforeTable. It is because your return type is List<MoodBeforeTable> but you have used joins using TwistedThinkingTable and MoodAfterTable and so on.
What you should do is create a new POJO like below:
public class MoodLogPojo() {
private int userId;
private String moodBefore;
zprivate int cbtId;
private String automaticThought;
private int twistedThinkingPK;
private String challengeThought;
private String rationalThought;
private String date;
private String moodAfter;
private int twistedThinkingPK;
private String allOrNothing;
private String blamingOthers;
private String catastrophizing;
private String emotionalReasoning;
private String fortuneTelling;
private String labelling;
private String magnifyingTheNegative;
private String mindReading;
private String minimisingThePositive;
private String overGeneralisation;
private String selfBlaming;
private String shouldStatement;
// generate getters and setters too
public void setSelfBlaming(Stirng selfBlming) {
this.selfBlming = selfBlming
}
public String getSelfBlaming() { return selfBlaming; }
// and so on ...
}
Then use this class as the return type like :
LiveData<List<MoodLogPojo>> moodLogsAll (int userId, String date);.
NOTE: Mind the MoodLogPojo class. Modify it accoring to the corresponding data types from each Entity.
I have the following Class:
#DatabaseTable
public class BodyWeight implements Serializable {
#DatabaseField(generatedId = true, useGetSet = true, columnName = "id")
private Long id;
#DatabaseField
private String name;
#DatabaseField
private double goal;
#DatabaseField
private String primaryunit;
#DatabaseField
private String secondaryunit;
#DatabaseField
private int secondarysize;
#DatabaseField
private Collection<Collection<Double>> data;
How could I add a list of list of doubles primitives to database? What is the process? Should I create more classes for the List of list of doubles?
One possible way would be to keep Collection<Collection<Double>> data in your class and store it as JSON string in database with using custom persister. Like this
#DatabaseField(persisterClass = MyCustomPersister.class)
Collection<Collection<Double>> data;
Where MyCustomPersister should implement com.j256.ormlite.field.DataPersister or one of available implementations. Basically just two methods:
#Override
public Object resultToSqlArg();
#Override
public Object sqlArgToJava();
How could I add a list of list of doubles primitives to database? What is the process?
This is pretty complex. One way is just to make the type be serializable.
#DatabaseField(dataType = DataType.SERIALIZABLE)
private Collection<Collection<Double>> data;
That, like #unnamed_b's answer will store it in place as a serialized block of bytes. This won't work if you have a large number of doubles however.
If you want to store it as objects in another table then you are going to have to define these objects. Something like:
#DatabaseField(generatedId = true)
private long id;
#ForeignCollectionField
private Collection<DoubleCollection> data;
ORMLite only handles straight collections so we need to define the sub-collection:
#DatabaseTable
public class DoubleCollection {
#DatabaseField(generatedId = true)
private long id;
#ForeignCollectionField
private Collection<DoubleWrapper> data;
}
If you need to store a collection of doubles then you need to define a wrapper to hold an id and your double value.
#DatabaseTable
public class DoubleWrapper {
#DatabaseField(generatedId = true)
private long id;
#DatabaseField
private double value;
}
I'm using realm to store my data on Android. Awesome framework! Now the only problem I'm now having is:
I got a array list strings with id's of Countries in my database.
Now I retrieve my Drinks that contains a relationship to countries.
Is there a way that I could to do a query like this:
String [] ids;
realm.where(Drinks.class).equalsTo("country.id", ids);
Something like that?
Or do I really need to do a query to get me all drinks and then filter the list manually?
EDIT:
My classes:
public class Drinks extends RealmObject {
#PrimaryKey
private String id;
private String name;
private Country country;
}
public class Country extends RealmObject {
#PrimaryKey
private String id;
private String name;
}
What you want to do is possible with link queries in theory (searching for "country.id"), however link queries are slow. Also you'd need to concatenate a bunch of or() predicates together, and I would not risk that with a link query.
I would recommend using the following
public class Drinks extends RealmObject {
#PrimaryKey
private String id;
private String name;
private Country country;
#Index
private String countryId;
}
public class Country extends RealmObject {
#PrimaryKey
private String id;
private String name;
}
And when you set the Country in your class, you also set the countryId as country.getId().
Once you do that, you can construct such:
RealmQuery<Drinks> drinkQuery = realm.where(Drinks.class);
int i = 0;
for(String id : ids) {
if(i != 0) {
drinkQuery = drinkQuery.or();
}
drinkQuery = drinkQuery.equalTo("countryId", id);
i++;
}
return drinkQuery.findAll();
Since the Realm database has added RealmQuery.in() with the version 1.2.0
I suggest using something like this.
//Drinks
public class Drinks extends RealmObject {
#PrimaryKey
private String id;
private String name;
private String countryId;
//getter and setter methods
}
//Country
public class Country extends RealmObject {
#PrimaryKey
private String id;
private String name;
//getter and setter methods
}
The code to use inside activity/fragments to retrieve drink list
String[] countryIdArray = new String[] {"1","2","3"} //your string array
RealmQuery<Drinks> realmQuery = realm.where(Drinks.class)
.in("countryId",countryIdArray);
RealmResults<Drinks> drinkList = realmQuery.findAll();
In latest version of Realm 7+, you can use anyOf to match a field against a list of values.
anyOf("name", new String[]{"Jill", "William", "Trillian"})
in older versions, use in instead of anyOf and with kotlin use oneOf instead of in.
see this issue
To match a field against a list of values, use in. For example, to find the names “Jill,” “William,” or “Trillian”, you can use in("name", new String[]{"Jill", "William", "Trillian"}). The in predicate is applicable to strings, binary data, and numeric fields (including dates).
Doc.-> https://realm.io/docs/java/latest#queries
"tipolistView.setAdapter(listViewArrayAdapter)Is it possible to sort a JsonArray by a key?
I mean, I have a listview , and it is being created this way:
{"id":"1","nome":"glamourhood","tipo":"1"},
{"id":"2","nome":"Face da Mia","tipo":"2"},
{"id":"5","nome":"Team Transformerz","tipo":"3"},
{"id":"6","nome":"Face da Team de novo","tipo":"4"},
{"id":"7","nome":"Tiago Faria Fitness","tipo":"5"},
{"id":"8","nome":"Nuno Soares","tipo":"6}
And I wanted it sorted by "tipo" from smaller to bigger, or even better : by type * id (that would be awesome).
Is this achievable on Android?
deserialize your json into objects, like
(assumed these are movie titles)
#Serializable
public class Movie {
private int id;
#SerializedName("nome")
private String name;
private int tipo;
public Movie();
//getter & setter
}
For deserializing you could use GSON for instance. I've added an example for mapping json fields to different fields in an object (nome and name) when using GSON.
I can't come up with code for deserializing right now, but you will find plenty sources on the web. It must be somethiong like:
final Movie movie = gson.fromJson(yourJsonInputReader, Movie.class);
After deserializing those JSONs to objects, you may have a List<Movie> movies. Now you could sort this list in any way you want, use a CustomCoparator for this purpose.
public class MovieComparator implements Comparator<Movie>{
public enum Field {
ID, TIPO;
}
private Field field;
public MovieComparator(Field field) {
this.field = field;
}
#Override
public int compare(Movie mov1, Movie mov2) {
int comparison = 0;
switch(field) {
case ID:
comparison = mov1.getId().compareTo(mov2.getId());
case TIPO:
comparison = mov1.getTipo().compareTo(mov2.getTipo());
}
return comparison;
}
Then use it like:
Collections.sort(movies, new MovieComparator(MovieComparator.Field.ID));
Let me know if this works out or not, can't check it, because spending time with my son ;)
I use ormlite and I have a db with a field:
public static final String NAME = "name";
#DatabaseField (canBeNull = false, dataType = DataType.SERIALIZABLE, columnName = NAME)
private String[] name = new String[2];
And I would like to get all elements that name[0] and name[1] are "car". I try to add a where clausule like:
NAMEDB nameDB = null;
Dao<NAMEDB, Integer> daoName = this.getHelper().getDao(NAMEDB.class);
QueryBuilder<NAMEDB, Integer> queryName = daoName.queryBuilder();
Where<NAMEDB, Integer> where = queryName.where();
where.in(nameDb.NAME, "car");
But it doesn't work because it's an array string.
I have other fields:
public static final String MARK = "mark";
#DatabaseField (canBeNull = false, foreign = true, index = true, columnName = MARK)
private String mark = null;
And I can do this:
whereArticulo.in(nameDB.MARK, "aaa");
How can I solve my problem? Thanks.
It seems to me that a third option to store a string array (String[] someStringArray[]) in the database using Ormlite would be to define a data persister class that converts the string array to a single delimited string upon storage into the database and back again to a string array after taking it out of the database.
E.g., persister class would convert ["John Doe", "Joe Smith"] to "John Doe | Joe Smith" for database storage (using whatever delimiter character makes sense for your data) and converts back the other way when taking the data out of the database.
Any thoughts on this approach versus using Serializable or a foreign collection? Anyone tried this?
I just wrote my first persister class and it was pretty easy. I haven't been able to identify through web search or StackOverflow search that anyone has tried this.
Thanks.
As ronbo4610 suggested, it is a good idea to use a custom data persister in this case, to store the array as a string in the database separated by some kind of delimiter. You can then search the string in your WHERE clause just as you would any other string. (For example, using the LIKE operator)
I have implemented such a data persister. In order to use it, you must add the following annotation above your String[] object in your persisted class:
#DatabaseField(persisterClass = ArrayPersister.class)
In addition, you must create a new class called "ArrayPersister" with the following code:
import com.j256.ormlite.field.FieldType;
import com.j256.ormlite.field.SqlType;
import com.j256.ormlite.field.types.StringType;
import org.apache.commons.lang3.StringUtils;
public class ArrayPersister extends StringType {
private static final String delimiter = ",";
private static final ArrayPersister singleTon = new ArrayPersister();
private ArrayPersister() {
super(SqlType.STRING, new Class<?>[]{ String[].class });
}
public static ArrayPersister getSingleton() {
return singleTon;
}
#Override
public Object javaToSqlArg(FieldType fieldType, Object javaObject) {
String[] array = (String[]) javaObject;
if (array == null) {
return null;
}
else {
return StringUtils.join(array, delimiter);
}
}
#Override
public Object sqlArgToJava(FieldType fieldType, Object sqlArg, int columnPos) {
String string = (String)sqlArg;
if (string == null) {
return null;
}
else {
return string.split(delimiter);
}
}
}
Unfortunately ORMLite does not support querying fields that are the type SERIALIZABLE. It is storing the array as a serialized byte[] so you cannot query against the values with an IN query like:
where.in(nameDb.NAME, "car");
ORMLite does support foreign collections but you have to set it up yourself with another class holding the names. See the documentation with sample code:
http://ormlite.com/docs/foreign-collection