Can`t query using 'where' between two tables in one DB? - android

Today one problem came to me when I was learning Room in Android.
Everything is ok but I just can`t query with where between two tables.
Here are my codes:
......................................................................................................................................................
this code works well
#Query("select users.id,users.name from users where score > :score and assist > :assist")
List<UserSimple> getUserWithLimits(int score,int assist);
but the follow one can`t get anything:
#Query("select users.id,users.name from users,performs where users.id = performs.id and performs.score > :score and performs.assist > :assist")
List<UserSimple> getUserWithLimits(int score,int assist);
and here are my tables created using Room:
........................................................................................................................................................
user table:
#Entity(tableName = "users",
primaryKeys = {"id", "name"},
indices = {
#Index(value = "id", unique = true)
})
public class User {
#android.support.annotation.NonNull
#ColumnInfo(name = "id")
private String id;
#android.support.annotation.NonNull
#ColumnInfo(name = "name")
private String name;
#ColumnInfo(name = "position")
private String position;
#Embedded
private UserPerforms performs;
#Ignore
public User() {
}
public User(String id, String name, String position, UserPerforms performs) {
this.id = id;
this.name = name;
this.position = position;
this.performs = performs;
}
getters/setters/toString()...
}
........................................................................................................................................................
performs table:
#Entity(tableName = "performs",
primaryKeys = "p_id",
foreignKeys = #ForeignKey(entity = User.class
, parentColumns = "id"
, childColumns = "p_id")) //定义主键
public class UserPerforms {
#android.support.annotation.NonNull //
#ColumnInfo(name = "p_id")
private String p_id;
#ColumnInfo(name = "score")
private int score;
#ColumnInfo(name = "assist")
private int assist;
#Ignore
public UserPerforms() {
}
public UserPerforms(String p_id, int score, int assist) {
this.p_id = p_id;
this.score = score;
this.assist = assist;
}
...getters/setters/toString()..
}
........................................................................................................................................................
userSimple class:
public class UserSimple {
#ColumnInfo(name = "id")
private String id;
#ColumnInfo(name = "name")
private String name;
...getters/setters/toString()
public UserSimple(String id, String name) {
this.id = id;
this.name = name;
}
}
Anyone can help me?Thanks in advance.

You are joining wrong columns. Your id column in the performs table is p_id, not id. Try this:
#Query("select users.id,users.name from users,performs where users.id = performs.p_id and performs.score > :score and performs.assist > :assist")

Related

Room : incorrect result of a query with a date condition

This query is retrieving all the records whatever the date for the pet :
#Query("SELECT * FROM Fooding WHERE pet_Id = :petId AND date(fooding_date) = date(current_timestamp)")
Flowable<List<Fooding>> getDailyFoodingsForPet (Long petId);
Converters :
private static final DateTimeFormatter dtf = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
#androidx.room.TypeConverter
public static OffsetDateTime toOffsetDateTime(String value) {
return value == null ? null : OffsetDateTime.parse(value,dtf);
}
#androidx.room.TypeConverter
public static String fromOffsetDateTime(OffsetDateTime value) {
return value == null ? null : value.format(dtf);
}
Entity :
public class Fooding implements Parcelable {
#NonNull
#PrimaryKey(autoGenerate = true)
private Long foodingId;
#NonNull
#ColumnInfo(name = "user_Id")
private Long userId;
#NonNull
#ColumnInfo(name = "pet_Id")
private Long petId;
#TypeConverters(DataTypeConverter.class)
#ColumnInfo(name = "fooding_date")
private OffsetDateTime foodingDate;
private Integer quantity;
Does anyone have any idea of ​​the problem ?
Edit : this query have the same result :
#Query("SELECT * FROM Fooding WHERE pet_Id = :petId AND date(fooding_date) = date('now')")
Flowable<List<Fooding>> getDailyFoodingsForPet (Long petId);

How to obtain count of parent foreign key from child table using Room

I have a parent entity Collection:
#Entity(tableName = "collections")
public class Collection implements Serializable {
#PrimaryKey
#NonNull
public String id;
public String collTitle;
public int isFavorite;
public int wordCount;
Collection(String collTitle, int isFavorite, int wordCount) {
this(UUID.randomUUID().toString(), collTitle, isFavorite, wordCount);
}
#Ignore
Collection(#NonNull String id, String collTitle, int isFavorite, int wordCount) {
this.id = id;
this.collTitle = collTitle;
this.isFavorite = isFavorite;
this.wordCount = wordCount;
}
}
and a child entity Word:
#Entity(tableName = "words",
foreignKeys = #ForeignKey(
entity = Collection.class,
parentColumns = "id",
childColumns = "collId",
onDelete = SET_DEFAULT),
indices = #Index("collId"))
public class Word implements Serializable {
#PrimaryKey
#NonNull
public final String id;
public String wordTitle;
public String collId;
public String pageNum;
public int isFavorite;
public String wordNotes;
#Ignore
Word(String wordTitle, String collId, String pageNum, int isFavorite, String wordNotes) {
this(UUID.randomUUID().toString(), wordTitle, collId, pageNum, isFavorite, wordNotes);
}
Word(#NonNull String id, String wordTitle, String collId, String pageNum, int isFavorite,
String wordNotes) {
this.id = id;
this.wordTitle = wordTitle;
this.collId = collId;
this.pageNum = pageNum;
this.isFavorite = isFavorite;
this.wordNotes = wordNotes;
}
}
At the time of inserting a new Collection, I give wordCount as 0 because every new collection would have 0 words associated with it. However, when inserting a new Word, I have to choose one collection from the defined collections and use its 'id' as 'collId' (Foreign Key).
Now I need to retrieve a list of Collection objects with 'wordCount' field containing the actual number of words associated with each Collection object. As already mentioned, 'wordCount' field is assigned a value of 0 at the time of insertion of a Collection object.
I just hope I made my question clear. Kindly suggest a query that serves my purpose. And I don't want to have the result in the form of a new POJO class like, for example, CollectionsAndWords.
Any help would be a great help!
OK, i solved it in the following way:
In my Collection entity, I annotated the wordCount as follows:
#ColumnInfo(name = "word_count")
public int wordCount;
and made changes to the constructors by removing this field:
Collection(String collTitle, int isFavorite) {
this(UUID.randomUUID().toString(), collTitle, isFavorite);
}
#Ignore
Collection(#NonNull String id, String collTitle, int isFavorite) {
this.id = id;
this.collTitle = collTitle;
this.isFavorite = isFavorite;
}
Finally, I added the following query method in my DAO:
#Query("SELECT collections.id, collections.collTitle, collections.isFavorite, " +
"COUNT(words.collId) as word_count " +
"FROM collections " +
"LEFT JOIN words " +
"ON collections.id = words.collId " +
"GROUP BY collections.id " +
"ORDER BY collections.collTitle")
List<Collection> findAllCollsWithCount();
The LEFT JOIN used in the right manner did all the trick for me.
Note that in above query, I'm not retrieving the wordCount field, I'm just letting a new field to be calculated and mapping it to wordCount. If I retrieve wordCount along with other columns from collections table, I get 02 columns that go by the name of word_count; one with 0 value and other with calculated value (COUNT()). I also tried to annotate wordCount with #Ignore but then Room couldn't find any column to map word_count to.
However, for now, the above solution is perfectly serving my purpose, so it is the answer. It might help someone with the same question.
Thanks!

Try to get average value from Android Room Persistence Library with dynamic conditions

I am trying to get average value if two conditions using Android Room Persistence Library, my entity looks like this:
public class FinishedTask {
private static final String TASK_NAME_COLUMN = "taskName";
private static final String DEPARTMENT_NAME_COLUMN = "departmentName";
private static final String EMPLOYEE_NAME_COLUMN = "employeeName";
private static final String TIME_UNTIL_DOME_NAME_COLUMN = "timeUntilDoneName";
private static final String SAVED_DATE_NAME_COLUMN = "savedDateName";
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name = "id")
private long id = 0;
#ColumnInfo(name = "passedMilliseconds")
private long passedMilliseconds = 0;
#ColumnInfo(name = TASK_NAME_COLUMN)
private String taskName = TASK_NAME_COLUMN;
#ColumnInfo(name = DEPARTMENT_NAME_COLUMN)
private String departmentName = DEPARTMENT_NAME_COLUMN;
#ColumnInfo(name = EMPLOYEE_NAME_COLUMN)
private String employeeName = EMPLOYEE_NAME_COLUMN;
#ColumnInfo(name = TIME_UNTIL_DOME_NAME_COLUMN)
private long timeUntilDone = 0;
#ColumnInfo(name = SAVED_DATE_NAME_COLUMN)
private long savedDate = 0;
public FinishedTask(){}
}
My Query looks like this:
#Query("SELECT AVG(timeUntilDoneName) FROM finishedTasks WHERE :column1=:value1 AND :column2=:value2")
Single<Long> getAverageTime(String column1, String value1, String column2, String value2);
And I got error:
Query returned empty result set: SELECT AVG(timeUntilDoneName) FROM finishedTasks WHERE ?=? AND ?=?
When I change query to:
#Query("SELECT AVG(timeUntilDoneName) FROM finishedTasks WHERE taskName=:value1 AND :departmentName=:value2")
Single<Long> getAverageTime(String value1, String value2);
Everything works fine and as expected. What am I doing wrong?
You can only use placeholders where SQLite itself supports placeholders, and SQLite does not support replacing column names with placeholders.

how can I add rows to DB on android only when DB is created? (using room)

I have category class:
#Entity(tableName = "Categories",indices = {#Index(value = {"id"},
unique = true)})
public class Category implements Serializable {
public Category(String name,int icon,int color)
{
_name= name;
_icon = icon;
_color = color;
}
#PrimaryKey(autoGenerate = true)
public int id;
#ColumnInfo(name = "name")
public String _name;
#ColumnInfo(name = "icon")
public int _icon;
#ColumnInfo(name = "color")
public int _color;
public String get_name() {return _name;}
public int getColor() {
return _color;
}
public int getIcon() {
return _icon;
}
}
and I would like to create constant rows only when DB is newly created and not each time the application is loading.
what I did till now is:
protected CategorySingletone() {
// Exists only to defeat instantiation.
AppDatabase db = AppDatabase.getAppDatabase(MainActivity.get().getApplicationContext());
if (db.categoryDao().countCategories()==0) {
_categoryList = new ArrayList<>();
_categoryList.add(new Category("Cars", R.drawable.couch, 3));
_categoryList.add(new Category("Tech", R.drawable.phone, 3));
_categoryList.add(new Category("Home", R.drawable.book_1, 3));
_categoryList.add(new Category("Leisure", R.drawable.book_1, 3));
_categoryList.add(new Category("Motors", R.drawable.book_4, 3));
_categoryList.add(new Category("Fashion", R.drawable.book_5, 3));
for (Iterator<Category> i = _categoryList.iterator(); i.hasNext();) {
Category item = i.next();
db.categoryDao().insertAll(item);
}
}
while I am checking if rows exists.
is there a better way?
A more efficient way would be to use the DatabaseUtils queryNumEntries method.
e.g.
if (DatabaseUtils.queryNumEntries(db,"Categories") == 0) {
.......
}

How to get foreign DatabaseField automatically with query?

I'm using ORMLite (v4.48) with my Android app. I have the table "Contact" which can contain multiple "Email" (ForeignCollectionField) and one "Personal" (DatabaseField) object. When I get the Contact object from the database I would like to automatically get (or lazy load) the Personal object which has the same Contact ID.
It already automatically gets the Email objects which I can access. But for some reason the Personal object is always "null" even though there is an entry in the Personal table.
Here are my classes:
#DatabaseTable(tableName = "Contact", daoClass = ContactDao.class)
public class Contact {
#DatabaseField(generatedId = true, columnName = PersistentObject.ID)
int id;
#DatabaseField(index = true)
String contactName;
#ForeignCollectionField(eager = false)
ForeignCollection<Email> emails;
#DatabaseField(foreign = true)
public Personal personal;
public ForeignCollection<Email> getEmails() {
return emails;
}
public void setEmails(ForeignCollection<Email> emails) {
this.emails = emails;
}
public Personal getPersonal() {
return personal;
}
public void setPersonal(Personal personal) {
this.personal = personal;
}
...
}
And
#DatabaseTable(tableName = "Email", daoClass = EmailDao.class)
public class Email {
#DatabaseField(generatedId = true, columnName = PersistentObject.ID)
int id;
#DatabaseField(foreign = true, foreignAutoRefresh = true, columnName = PersistentObject.CONTACT_ID_FIELD_NAME) // contact_id
Contact contact;
#DatabaseField
String emailType;
#DatabaseField(canBeNull = false)
String email;
public Email() {
}
public Email(int id, Contact Contact, String emailType, String email) {
this.id = id;
this.contact = contact;
this.emailType = emailType;
this.email = email;
}
public int getId() {
return id;
}
public Contact getContact() {
return contact;
}
public void setContact(Contact contact) {
this.contact = contact;
}
public String getEmailType() {
return emailType;
}
public void setEmailType(String emailType) {
this.emailType = emailType;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
...
}
and
#DatabaseTable(tableName = "Personal", daoClass = PersonalDao.class)
public class Personal {
#DatabaseField(generatedId = true, columnName = PersistentObject.ID)
int id;
#DatabaseField(foreign = true, foreignAutoRefresh = true, columnName = PersistentObject.CONTACT_ID_FIELD_NAME)
Contact contact;
#DatabaseField
int age;
#DatabaseField
int weight; // in grams
#DatabaseField
int height; // in cm
public Personal() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Contact getContact() {
return contact;
}
public void setContact(Contact contact) {
this.contact = contact;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
I'm getting the data from the database like this:
QueryBuilder<Contact, Integer> queryBuilder = mContactDao.queryBuilder();
queryBuilder.orderBy("lastViewed", false);
queryBuilder.limit(limit);
PreparedQuery<Contact> preparedQuery = queryBuilder.prepare();
List<Contact> contactList = mContactDao.query(preparedQuery);
that all works well so far.
Then further down the code I can access the Email objects like this:
ForeignCollection<Email> emails = contact.getEmails();
Iterator<Email> iter = emails.iterator();
while (iter.hasNext()) {
Email iAddress = iter.next();
Log.d(TAG, "EMAIL: " + iAddress.getEmail());
Log.d(TAG, "EMAIL TYPE: " + iAddress.getEmailType());
}
Which also works perfectly. Only if I want to access the Personal object I always get NULL.
Personal personal = contact.getPersonal(); // is always NULL
I can't figure out why that is. Do I manually need to add a JOIN in the query builder? I thought it would also lazily load the data once I access it with getPersonal() like it does with getEmails()?
You did not show how entity instances are created, but i assume Personal is created after Contact has been inserted. If that is a case, then after inserting Personal you should do contact.setPersonal(personal), and contactDao.update(contact) - that way personal_id will be stored in contact row

Categories

Resources