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) + "";
Related
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);
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);
I updated my AbstractFooEntity class by adding an integer field like below, and I bumped the DB version (the DB is initialized with new DatabaseSource(context, Models.DEFAULT, DB_VERSION).
#Entity
abstract class AbstractFooEntity {
// this was in DB schema v1
String someField;
// added in DB schema v2
int newField = 0;
}
When I deploy this code and the (automatic) DB migration is performed when the user runs the new version of the Android app, I get the following error at runtime: "Cannot add a NOT NULL column with default value NULL".
What's the proper way to annotate the entity so that the framework correctly handles the automatic DB migration in this scenario?
I found a solution of this.
database.execSQL("ALTER TABLE table_name ADD COLUMN colum_name INTEGER DEFAULT 1 not null");
add the command : "DEFAUT value" after data type will solve your problem.
There are two options, first one is probably to be preferred - in the second one, you need to handle possible nullpointers in the code:
option 1
#Entity
abstract class AbstractFooEntity {
...
#Column(value = "0")
int newField;
}
option 2
#Entity
abstract class AbstractFooEntity {
...
Integer newField;
}
I am using Ormlite and I have an object that has a foreign field.
The said object also has getters and setters for it's fields.
public class Object {
#DatabaseField(foreign = true)
private Object2 foreignField;
Object() {
}
public Object2 getForeignField(){ return foreignField; }
public void setForeignField(Object2 foreignField){
this.foreignField = foreignField;
}
}
So I assumed that when I call :
Object testObject;
Object2 testObject2;
testObject.setForeignField(testObject2);
getDao.update(testObject);
It will automatically update the testObject in the database with the new foreignfield's id, but my table is not updating.
What am I doing wrong?
EDIT :
By reading the actual documentation on Ormlite, the update(Object) method will not update any foreign objects or foreign collections.
http://ormlite.com/javadoc/ormlite-core/com/j256/ormlite/dao/Dao.html#update(T)
NOTE: This will not save changes made to foreign objects or to foreign collections.
And now because of that, how do I update a foreign object on a table?
It will automatically update the testObject in the database with the new foreignfield's id, but my table is not updating.
It certainly should be.
The update(...) call doesn't compare the object with the database so a SQL UPDATE statement will be made. Have you tried turning on ORMLite logging?
If it is updating the Object with the same id from the Object2 foreignField then maybe that id is the same? When you call testObject.setForeignField(testObject2), the testObject2 should already have been created in the Object2 table. It needs to have an appropriate id field which is was gets stored in the Object table.
If you provide more details about the id field values and what the database has before and after the update, I may be able to help more.
I'm tring to make join in two tables and get all columns in both, I did this:
QueryBuilder<A, Integer> aQb = aDao.queryBuilder();
QueryBuilder<B, Integer> bQb = bDao.queryBuilder();
aQb.join(bQb).prepare();
This equates to:
SELECT 'A'.* FROM A INNER JOIN B WHERE A.id = B.id;
But I want:
SELECT * FROM A INNER JOIN B WHERE A.id = B.id;
Other problem is when taking order by a field of B, like:
aQb.orderBy(B.COLUMN, true);
I get an error saying "no table column B".
When you are using the QueryBuilder, it is expecting to return B objects. They cannot contain all of the fields from A in B. It will not flesh out foreign sub-fields if that is what you mean. That feature has not crossed the lite barrier for ORMLite.
Ordering on join-table is also not supported. You can certainly add the bQb.orderBy(B.COLUMN, true) but I don't think that will do what you want.
You can certainly use raw-queries for this although it is not optimal.
Actually, I managed to do it without writing my whole query as raw query. This way, I didn't need to replace my query builder codes (which is pretty complicated). To achieve that, I followed the following steps:
(Assuming I have two tables, my_table and my_join_table and their daos, I want to order my query on my_table by the column order_column_1 of the my_join_table)
1- Joined two query builders & used QueryBuilder.selectRaw(String... columns) method to include the original table's + the columns I want to use in foreign sort. Example:
QueryBuilder<MyJoinTable, MyJoinPK> myJoinQueryBuilder = myJoinDao.queryBuilder();
QueryBuilder<MyTable, MyPK> myQueryBuilder = myDao.queryBuilder().join(myJoinQueryBuilder).selectRaw("`my_table`.*", "`my_join_table`.`order_column` as `order_column_1`");
2- Included my order by clauses like this:
myQueryBuilder.orderByRaw("`order_column_1` ASC");
3- After setting all the select columns & order by clauses, it's time to prepare the statement:
String statement = myQueryBuilder.prepare().getStatement();
4- Get the table info from the dao:
TableInfo tableInfo = ((BaseDaoImpl) myDao).getTableInfo();
5- Created my custom column-to-object mapper which just ignores the unknown column names. We avoid the mapping error of our custon columns (order_column_1 in this case) by doing this. Example:
RawRowMapper<MyTable> mapper = new UnknownColumnIgnoringGenericRowMapper<>(tableInfo);
6- Query the table for the results:
GenericRawResults<MyTable> results = activityDao.queryRaw(statement, mapper);
7- Finally, convert the generic raw results to list:
List<MyTable> myObjects = new ArrayList<>();
for (MyTable myObject : results) {
myObjects.add(myObject);
}
Here's the custom row mapper I created by modifying (just swallowed the exception) com.j256.ormlite.stmt.RawRowMapperImpl to avoid the unknown column mapping errors. You can copy&paste this into your project:
import com.j256.ormlite.dao.RawRowMapper;
import com.j256.ormlite.field.FieldType;
import com.j256.ormlite.table.TableInfo;
import java.sql.SQLException;
public class UnknownColumnIgnoringGenericRowMapper<T, ID> implements RawRowMapper<T> {
private final TableInfo<T, ID> tableInfo;
public UnknownColumnIgnoringGenericRowMapper(TableInfo<T, ID> tableInfo) {
this.tableInfo = tableInfo;
}
public T mapRow(String[] columnNames, String[] resultColumns) throws SQLException {
// create our object
T rowObj = tableInfo.createObject();
for (int i = 0; i < columnNames.length; i++) {
// sanity check, prolly will never happen but let's be careful out there
if (i >= resultColumns.length) {
continue;
}
try {
// run through and convert each field
FieldType fieldType = tableInfo.getFieldTypeByColumnName(columnNames[i]);
Object fieldObj = fieldType.convertStringToJavaField(resultColumns[i], i);
// assign it to the row object
fieldType.assignField(rowObj, fieldObj, false, null);
} catch (IllegalArgumentException e) {
// log this or do whatever you want
}
}
return rowObj;
}
}
It's pretty hacky & seems like overkill for this operation but I definitely needed it and this method worked well.