Select multipile column through Room liberary - android

I want to select multiple column from SqLite through Room Library in Android SDK environment.
Below is the query for selecting it.
#Query("SELECT ID,message,timestamp FROM Chat_Message WHERE groupID =:groupID
ORDER BY timestamp DESC LIMIT 1")
public List get_last_msg_ID_timestamp (String
groupID);
My Last_Msg_Detail class which is define under main class is as follows:-
public class Last_Msg_Detail {
public Integer ID;
public String message;
public Long timestamp;
}
For accessing this three variable have created below method :-
Last_Msg_Detail last_record_t = new Last_Msg_Detail();
public Last_Msg_Detail get_last_msgand_time_stamp(String groupID){
List<Last_Msg_Detail> last_record =
chat_messageDao.get_last_msg_ID_timestamp(groupID);
last_record_t = last_record.get(0);
return last_record_t;
}
On Rebuilding Project, getting follow error
1. error: Cannot figure out how to save this field into database. You can
consider adding a type converter for it.
2. error: Not sure how to convert a Cursor to this method's return type
Kindly advise how to resolve.
Thanks in advance for your help.

your method return custom object and the object has a lot of fields.
so, when you try to return specific columns, you try to return a new object. so the error occurs.
to solve the problem, create a new object for the selected columns. it has to has these fields.
ID,message,timestamp
and use the object in your method
#Query("SELECT ID,message,timestamp FROM Chat_Message WHERE groupID =:groupID ORDER BY timestamp DESC LIMIT 1")
public List<NEW_OBJECT> get_last_msg_ID_timestamp (String groupID);

Related

OColumn with odoo functional in Odoo Mobile Framework not working

I have this OColumn partner_name = new OColumn("Partner", OVarchar.class).setLocalColumn(); in my sale order model class with odoo functional method that depends on partner_id column. I would like to search the partner_name in my list using that column partner_name, but I'm a little confused on how to achieve this. Please needed some help.
This is what I've tried:
BaseFragment
#Override
public void onViewBind(View view, Cursor cursor, ODataRow row) {
getPartnerIds(row);
OControls.setText(view, R.id.partner_name, row.getString("partner_name")); // displays false
....
}
}
private void getPartnerIds(ODataRow row){
OValues oValues = new OValues();
oValues.put("partner_id", row.get("partner_id"));
saleOrder.storeManyToOne(oValues);
}
updated:
I noticed that even though I created
#Odoo.Functional(method = "storeManyToOne", store = true, depends = {"partner_id"})
OColumn partner_name = new OColumn("Partner", OVarchar.class).setLocalColumn();
no column was created.
Updated:
partner_name column with odoo functional
Edit: Just place the 'if (type.isAssignableFrom(Odoo.Functional.class)'
before the 'if (type.getDeclaringClass().isAssignableFrom(Odoo.api.class))' to have the correct values.
Define the partner_name field like below:
#Odoo.Functional(method="storePartnerName", store=true, depends={"partner_id"})
OColumn partner_name = new OColumn("Partner name", OVarchar.class)
.setLocalColumn();
public String storePartnerName(OValues values) {
try {
if (!values.getString("partner_id").equals("false")) {
JSONArray partner_id = new JSONArray(values.getString("partner_id"));
return partner_id.getString(1);
}
} catch (Exception e) {
e.printStackTrace();
}
return "false";
}
You can simply get the partner_name using:
row.getString("partner_name")
EDIT:
Note that database is created when you first time run your application, or when you clean your data from app
setting. You need to clean application data everytime when you update your database column.
If the column was added after the database creation, it will not be added to the corresponding table. This is because the database is not upgraded. To fix this issue you can:
Clean application data to update your database column
Remove user account (This will delete database) or reinstall the application to recreate the database.
Or you can change DATABASE_VERSION in odoo/datas/OConstants then override onModelUpgrade method in sale order model and upgrade the table manually (alter sale order table and add the partner name column using SQL query: ALTER TABLE sale_order ADD partner_name VARCHAR(100)).
When a new sale order is created and synchronized, the partner name should be computed and stored automaticaly.
I noticed that the partner name was not set for existing records after synchrinization so I added another SQL query to compute and set the value of partner name for old records.
Example:
#Override
public void onModelUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("ALTER TABLE sale_order ADD partner_name VARCHAR(100)");
db.execSQL("UPDATE sale_order SET partner_name = (SELECT name from res_partner WHERE _id=partner_id) WHERE partner_name IS NULL AND partner_id IS NOT NULL");
}
Edit (config):
using the new configuration you will get the following error (which will prevent creating fields using annotations):
W/System.err: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.Class.isAssignableFrom(java.lang.Class)' on a null object reference
W/System.err: at com.odoo.core.orm.OModel.compatibleField(OModel.java:349)
CODE:
if (type.getDeclaringClass().isAssignableFrom(Odoo.api.class)) {
Try to remove .getDeclaringClass()
Edit: not all partner names are shown
There is a org.json.JSONException error that happens when it try to convert partner_id string to a JSON array.
W/System.err: org.json.JSONException: Unterminated array at character 12 of [114.0, UH PARTNER]
The error happens when it try to convert names containing spaces. To avoid that you can cast partner_id string to a list of objects.
In partnerName method, replace the following code:
JSONArray partner_id = new JSONArray(values.getString("partner_id"));
return partner_id.getString(1);
With:
List<Object> partner_id = (ArrayList<Object>) values.get("partner_id");
return partner_id.get(1) + "";

Return type of GROUP BY statement in Room Database

I would like to make the following query to my database:
SELECT type, COUNT(*) FROM offerings GROUP BY type
This query works well with an Sqlite browser. Now I want to use this query in my Dao:
#Query("SELECT type, COUNT(*) FROM offerings GROUP BY type")
LiveData<Map<String, Integer>> getOfferingsGroupedByType();
But I am getting the error: ... not sure how to convert a cursor to this method's return type
How can I query a table with 2 columns? --> that is, [type, count(type)] ?
Step #1: Give a name to the count: SELECT type, COUNT(*) AS count FROM offerings GROUP BY type
Step #2: Create a Java class with suitable fields:
public class Thingy {
public String type;
public int count;
}
Step #3: Have your return type from the DAO method use that class:
#Query("SELECT type, COUNT(*) FROM offerings GROUP BY type")
LiveData<List<Thingy>> getOfferingsGroupedByType();
I don't recall Room supporting returning a Map, so you will need to handle that aspect yourself, either in the observer or via a MediatorLiveData that wraps the LiveData you get from the DAO and does the conversion.

How do I perform a Room DAO multi table join #Query using select fields?

My Problem:
I'm struggling to eliminate the compiling error on the following Room #Query statement in a Room DAO. As you can see, the SQLite query statement is joining various fields from different tables. The missing fields identified by the error are a part of the Notes class constructor identified in the List type for the method. I think I need to change the List type identified. If I'm right, I need some guidance/suggestion on how I should resolve it. Do I need to create a new Class and DAO with just those specific fields queried? Or maybe just a class since there is not table specific to these fields only. The error is:
error: The columns returned by the query does not have the fields [commentID,questionID,quoteID,termID,topicID,deleted] in com.mistywillow.researchdb.database.entities.Notes even though they are annotated as non-null or primitive. Columns returned by the query: [NoteID,SourceID,SourceType,Title,Summary]
List getNotesOnTopic(String topic);
#Query("SELECT n.NoteID, s.SourceID, s.SourceType, s.Title, c.Summary FROM Comments as c " +
"LEFT JOIN Notes as n ON n.CommentID = c.CommentID " +
"LEFT JOIN Sources as s ON n.SourceID = s.SourceID " +
"LEFT JOIN Topics as t ON n.TopicID = t.TopicID WHERE t.Topic = :topic AND n.Deleted = 0")
List<Notes> getNotesOnTopic(String topic);
What I'm trying to do:
I'm attempting to convert and existing Java desktop app with an embedded an SQLite database. The above query does work fine in that app. I only want to pass field data from these tables.
What I've tried:
I've done some googling and visited some forums for the last few days (e.g. Android Forum, Developer.Android.com) but most of the Room #Query examples are single table full field queries (e.g. "Select * From table"). Nothing I found yet (there is probably something) quite addresses how and what to do if you are joining and querying only specific fields across tables.
I think I may have fixed my issue. I just created a new class called SourceTable and designated the queried fields in the constructor. The only catch was I, according to a follow up error, was that the parameters had to match the field names.
public class SourcesTable {
private int NoteID;
private int SourceID;
private String SourceType;
private String Title;
private String Summary;
public SourcesTable(int NoteID, int SourceID, String SourceType, String Title, String Summary){
this.NoteID = NoteID;
this.SourceID = SourceID;
this.SourceType = SourceType;
this.Title = Title;
this.Summary = Summary;
}
}
and then I update my list method:
List<SourcesTable> getNotesOnTopic(String topic);

Android Room Not Recognizing Column Name From Schema (using an alias for column name)

I am relatively new to Android Development and using its Room persistence library. The problem I am currently facing is the following error:
error: There is a problem with the query: [SQLITE_ERROR] SQL error or missing database (no such column: s_abb)
However my table schema (that this column is being referenced by) does contain this column by this name. Here is how I defined my entity in Android
#Entity
public class stops {
#PrimaryKey
#NonNull
#ColumnInfo(name = "s_name")
private String s_name;
#Ignore
#ColumnInfo(name = "s_abb")
private String s_abb;
#Ignore
#ColumnInfo(name = "Comments")
private String Comments;
public String getS_abb() {
return s_abb;
}
public void setS_abb(String s_abb) {
this.s_abb = s_abb;
}
public String getS_name() {
return s_name;
}
public void setS_name(String s_name) {
this.s_name = s_name;
}
public String getComments() {
return Comments;
}
public void setComments(String comments) {
Comments = comments;
}
}
I have tested the query in SQLite Studio and it does return expected data. Here is a screen shot of query written within DAO Interface: Query. I personally think the main problem is that Room may not recognize the aliases I am using with my subqueries and the column names. Am I correct in thinking this? I hope my screenshot helps. I did make sure to add proper spacing between SQL statements, as many solutions here have pointed out. If any of you need me to provide more information, I am happy to oblige! Thank you
As Vladimir Gladun pointed out, the column s_abb that I was querying for was set with an #Ignore annotation over it. Which as Android's documentation on #Ignore annotations states that "Ignores the marked element from Room's processing logic":
https://developer.android.com/reference/android/arch/persistence/room/Ignore.
Which basically means Room disregards it completely.
However this was not the only problem, My method was expecting Entity type values
whereas the SELECT statement from my outermost query was returning String type values. Fixing those two errors solved my problem.

How to insert a record with arbitrary id on a table with autoincrement using ORMLite on Android?

I need to pre-populate an SQLite database on my Android application.
My idea is to put an file into assets folder. Each line on this file contains a sql command like
INSERT INTO Books(id, name) VALUES(16, 'Book X');
The application will read line by line and will use raw query to insert the data into the database.
The problem is that id column has auto generated id. I think it will cause conflict with the use of an arbitrary id.
Someone knows how to use solve this problem?
The field with #DatabaseField annotation must have allowGeneratedIdInsert=true.
To avoid an exception, if the object with the id already exists, createOrUpdate method must be used instead create.
Edit: createOrUpdate is very time expensive. It's better use just create with great amounts of data.
This worked for me:
#DatabaseField(columnName = sqlId, generatedId = true, allowGeneratedIdInsert = true)
and no other column can have id=true
You can use the following (generatedId = true) to generate autoincrement integer id with database.
#DatabaseTable(tableName = "todo")
public class Todo {
public Todo() {
}
#DatabaseField(generatedId = true)
private Integer id;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}

Categories

Resources