I have the following database table object:
public class Goal {
#DatabaseField(generatedId = true)
private int id;
#DatabaseField
private String goal_title;
#DatabaseField
private String goal_desc;
#DatabaseField
private String goal_why;
...
}
I have added some rows to this table and now I want to write a query to update all the columns of a row in this table. I have seen documentation of ORM and could not get an idea how to write this query. Please help me how to write this query.
I have added some rows to this table and now I want to write a query to update all the columns of a row in this table.
I think you need to RTFM. I've spent a long time on the ORMLite documentation and I think it covers the UpdateBuilder pretty well. Feel free to ask more specific questions and I can add more details if not.
To quote from the docs:
The DAO can also be used to construct custom UPDATE and DELETE statements. Update statements are used to change certain fields in rows from the table that match the WHERE pattern - or update all rows if no where(). Delete statements are used to delete rows from the table that match the WHERE pattern - or delete all rows if no where().
To tweak the example code to use your Goal object:
UpdateBuilder<Goal, Integer> updateBuilder = goalDao.updateBuilder();
// update the goal_title and goal_why fields
updateBuilder.updateColumnValue("goal_title", "some other title");
updateBuilder.updateColumnValue("goal_why", "some other why");
// but only update the rows where the description is some value
updateBuilder.where().eq("goal_desc", "unknown description");
// actually perform the update
updateBuilder.update();
Hope this helps.
Related
I have a table in MySql and I named it FAQs and inside the table, There are two columns, Question column and Answer column, I want to get the data who inside the FAQs table and store it in the offline database but I got this message An entity must have at least 1 field annotated with #PrimaryKey
The Table
#Entity(tableName = "FAQs")
public class FAQModel {
private String question, answer;
public String getQuestion() {
return question;
}
public String getAnswer() {
return answer;
}
}
Is it possible to create a table in the Room without a primary key?
Yes you can, with some difficulty, but not via room annotation, and even still it would have a primary key so really the answer is No.
It is possible (e.g. via a callback) to create a table that does not appear to have a primary key column e.g. CREATE TABLE IF NOT EXISTS the_table (question TEXT, answer TEXT). However,
it would have a primary key on the column rowid which is normally hidden.
such a table would not be able to be readily used, as you would have to avoid Room's compilation time SQL statement checking.
you could also not take direct advantage of Room's underlying table to/from object handling.
However, you make the comment
But in the android app I only get the question and answer column and I am not getting faqId because I don't want to use it inside my app.
So you could have a POJO class that excludes the faqId column e.g.
class FAQModelLessIdColumn {
String question,answer;
}
Assuming that FAQModel is the entity and thus the tablename then with the above you could have an #Query such as:-
#Query("SELECT * FROM faqmodel")
abstract List<FAQModelLessIdColumn> getFAQModelsLessTheFaqIdColumn();
However, over time, you will probably learn that the primary key column, is highly beneficial as it MUST uniquely identify a single row in the table. So from a single value you can perform CRUD operations efficiently.
As an analogy consider the table as a list where the questions have been written down in no particular order. To find a question and it's answer How many days in a leap year then you would have to search the entire list until you found the question. If however the list was split into lists according to the first character of the question and these were maintained in order then by skipping to the H list would likely make finding the question easier. Thus indexes can greatly reduce search times. So having the faqId available enables searches via the primary index and they will be faster.
I have a column in my SQLite table named 'img_name'. An example of data in that column: '/storage/extSdCard/img1.jpg /storage/extSdCard/img2.jpg /storage/extSdCard/pic3.jpg'. Lets say I wanted to delete an image. I would delete the corresponding word(path). Only problem is, I do not know how to delete a specific word(path) from that column.
Any help will be appreciated.
The way to "delete a specific word" is to update the existing value.
So you will need an UPDATE statement which selects the appropriate rows, and changes the value of the column. The new value will have to be "computed" from the old value, as you would do in a programming language, using string functions.
UPDATE column1
SET column1 = trim(replace(column1||' ','/storage/extSdCard/img2.jpg ',''))
WHERE column2 = 'example'
Note that this is an example only. The correct string manipulation required may be different. Your question does not specify your exact requirements.
Please consult the SQLite documentation and internet articles for details of string functions in SQLite.
Note that this would not be necessary if you didn't store more than one value in a column in each row.
You should get id of your string that you need to remove, and then pass it in to this:
public void deleteById(int id)
{
SQLiteDatabase db=getWritableDatabase();
String[] position =new String[]{id+""};
db.delete("img_name", "id=?", position );
}
Note: "id=?". Replace "id" in this statement by your id column
How can we rename column name in ORMLite?
I am trying to write that query SELECT id as _id from some_table
Android Cursor Adapter requires us to have column named _id and ORMLite requires us to have column named id.
I am trying to write that query and return Cursor from this query.
Dao<NewsArticle, Long> newsArticleDao =
((SomeApp)mContext.getApplicationContext()).getDAOConnection().getDAO(
NewsArticle.class);
QueryBuilder<NewsArticle, Long> query = newsArticleDao.queryBuilder().selectRaw(
"`id` as `_id`");
PreparedQuery<NewsArticle> preparedQuery = query.prepare();
CloseableIterator<NewsArticle> iterator = newsArticleDao.iterator(preparedQuery);
AndroidDatabaseResults results =
(AndroidDatabaseResults)iterator.getRawResults();
cursor = results.getRawCursor();
That's what I have so far but I am getting this error when I pass query to iterator.
java.sql.SQLException: Could not compile this SELECT_RAW statement since the caller is expecting a SELECT statement. Check your QueryBuilder methods.
I guess I have to answer my question.
I still couldn't figure out how to rename column but I found the solution to problem.
Android Custom Adapter requires column named_id that's true but ORMLite doesn't require the column name to be id, I was wrong about that. It wants you to mark a column as id.
In my model, I marked my id and now it works like a charm.
#DatabaseField(id = true)
private long _id;
How can we rename column name in ORMLite?
Not sure I understand what you mean by rename. I don't think you mean schema change here. Are you talking about how to assign the name of the field in the database? You can do:
#DatabaseField(id = true, columnName = "_id")
private long id;
ORMLite requires us to have column named id.
Uh, no. ORMLite shouldn't care what the name of your column is. Maybe you are talking about Android?
I am trying to write that query and return Cursor from this query.
Is this is a different question?
java.sql.SQLException: Could not compile this SELECT_RAW statement since the caller is expecting a SELECT statement. Check your QueryBuilder methods.
You are getting this because you are calling:
newsArticleDao.queryBuilder().selectRaw(...);
And then calling:
query.prepare();
To quote from the javadocs of selectRaw(...)
... This will turn the query into something only suitable for the Dao.queryRaw(String, String...) type of statement.
I think you want to assign the name of your column using columnName. Have you looked at the javadocs for #DatabaseField? Or maybe look up "column name" in the online manual?
I am using a SQLite database to store data that can be used to reconstruct some objects that I am using in the application I am developing. I am storing CheckIns, Recipients, and ContactMethods.
These objects are related as follows:
CheckIn <--many -- to -- many--> Recipient
Recipient <--one -- to -- many--> ContactMethod
In Java, these objects' fields are defined as follows:
public class CheckIn {
private int id;
private boolean isEnabled;
private Date startTime;
private Repetition repetition;
private Set<Recipient> recipients;
}
public class Recipient {
private String name;
private Set<ContactMethod> contactMethods;
}
public class ContactMethod {
private String type;
private String address;
}
The database schema I have come up with for these objects is defined as follows:
CREATE TABLE checkIn(
_id INTEGER PRIMARY KEY AUTOINCREMENT,
isEnabled INTEGER,
startTime INTEGER,
repetitionNum INTEGER,
repetitionUnits TEXT
);
CREATE TABLE recipient(
_id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT
);
CREATE TABLE contactMethod(
_id INTEGER PRIMARY KEY AUTOINCREMENT,
type TEXT,
address TEXT,
recipientID INTEGER,
FOREIGN KEY(recipientID) REFERENCES recipient(_id) ON DELETE CASCADE
);
CREATE TABLE checkIn_recipient(
checkInID INTEGER,
recipientID INTEGER,
FOREIGN KEY(checkInID) REFERENCES checkIn(_id),
FOREIGN KEY(recipientID) REFERENCES recipient(_id)
);
I have two questions.
1. How do I efficiently INSERT a CheckIn to the database, along with its related objects?
To be more specific, if I have a CheckIn object in Java, not yet committed to the database, how can I structure an INSERT statement that will insert the CheckIn to the CheckIn table, but also store the new CheckIn's relation to one or more Recipients? It seems like to store the relation to the Recipients, I would need to already know the checkIn._id, which hasn't been set yet, since the CheckIn hasn't been entered into the database yet.
2. In Android, what is the best way to rebuild a CheckIn object, for example, from a database query?
I think I know the SQL query that I will need to get the right data:
SELECT checkIn.*, recipient.name, contactMethod.type, contactMethod.address
FROM checkIn
JOIN checkIn_recipient
ON (checkIn._id = checkIn_recipient.checkInID)
JOIN recipient
ON (checkIn_recipient.recipientID = recipient._id)
JOIN contactMethod
ON (recipient._id = contactMethod.recipientID)
This query will get me rows of data containing all of the information I need to build an object for every CheckIn and Recipient in the database, and I know how to get a Cursor object that will iterate through these rows. However, since the data required for a single CheckIn appears on multiple rows, I am confused about the best way to construct individual CheckIn objects. If I am trying to write a method like public Set<CheckIn> getAllCheckIns() that will return a set of all CheckIns that are stored in the database, do I need to run the query above, then loop through each row with the same checkIn._id, and within that loop, every row with the same recipient._id, and so forth? Is there any better way to do this?
I am sorry for the long question. I have only been working with SQL beyond single table databases since this morning, and I didn't want to leave out any important information. Let me know if I missed something.
Answer to Question 1: There are 2 possible ways.
a. You find the ID of the inserted row and use that to insert into the 2nd table. You can find the ID of inserted row if you are using the Android Insert method as documented here:
http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#insert%28java.lang.String,%20java.lang.String,%20android.content.ContentValues%29
Here you must ensure that all DB tables are committed or none.
b. You can create triggers. Triggers are database operations that are automatically performed when a specified database event occurs.
Learn how to create triggers: http://www.sqlite.org/lang_createtrigger.html
So for e.g. you can create a AFTER INSERT trigger that will be fired when a row in inserted in check in table. Then in that trigger you can insert a row into another table.
When the trigger is fired, you have access to the newly inserted row.
Answer to question 2:
I usually do the following :
Select from table 1 - Check In table
Iterate over the cursor and prepare the Check In object.
Within the loop, select from table 2 - Recipient table
Iterate over the recipient table and prepare the Check in object.
This would involve too many DB selects.
Alternatively, you could select all data once and then iterate to prepare the objects.
The point I am trying to make is that you have to iterate :D
Is the field "_id" necessary in Android SQLite?
_id is useful when you are using the enhanced Adapters which make use of a Cursor (e.g. ResourceCursorAdapter). It's used by these adapters to provide an ID which can be used to refer to the specific row in the table which relates the the item in whatever the adapter is being used for (e.g. a row in a ListView).
It's not necessary if you're not going to be using classes which need an _id column in a cursor, and you can also use "as _id" to make another column appear as though it's called _id in your cursor.
Why not make use of _ROWID_?
SQLite provides this anyway for every row, so you can just alias it to _id in your select statement.
Technically no the field _id is not required, however if you are making use of the CursorAdapter class (which you probably are, especially if you are working with the Notepad example) then yes
"The Cursor must include a column named "_id" or this class will not
work"
as explained in the documentation here. Unfortunately the code examples do not make this very clear.
It's quite convenient in many cases to have an id field. I prefer mine to be auto-incrementing (as shown below). I'm always finding new uses for the id field :)
When it comes time to attach the data to an adapter, I like to use a table name alias to query the id field as _id. Example: SELECT id _id, msg from message order by id. That way the adapter sees a field called _id and everybody's happy.
Here's a sample of how I define my tables:
CREATE TABLE message (_id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER, tripID TEXT, msg TEXT);
From the official docs...
The Cursor must include a column named "_id" or this class will not work. Additionally, using MergeCursor with this class will not work if the merged Cursors have overlapping values in their "_id" columns.
And the Cursor is:
This interface provides random read-write access to the result set returned by a database query.
In other words, you need _id for Android SQLite ( which usually uses Cursor )
If you define your _id column as an autoincrementing integer it is actually an alias for the ROWID column that SQLite provides by default (https://www.sqlite.org/lang_createtable.html#rowid).
Your create statement needs take the form...
CREATE TABLE t(_id INTEGER PRIMARY KEY ASC, y, z);
To prove this works...
UPDATE t SET _id=22 WHERE _id=11;
then
SELECT ROWID, _id FROM t;
and you'll find both _id and ROWID have the same value.
Note, that if you use DESC in the CREATE a new column is created and ROWID is not aliased.
Surely not.
Its a convenience field that some widgets like ListView uses to populate data. See this good article:
http://www.casarini.org/blog/2009/android-contentprovider-on-sqlite-tables-without-the-_id-column/
Of course if you are creating your own UI widget and your own adapter, you don't have to name your primary key as "_id". It can be any name you want. But you would be responsible for managing your collections of UI widgets and binding them to the right row in your database. "_id" is only useful for ListView as Brad has pointed out.
The _id field is indeed necessary in sqlite, it will help you to select a particular data from sqlite.
SELECT name from table_name where _id = ?
And if your are creating a recyclerview/ listview and you want a detailed activity for that list item you indeed need an id for this to fetch data of that item.
if you are creating a class for constants there is a BaseColumn interface in android,
which provide _ID field to that constant class.
//from android documentation..
public static class FeedEntry implements BaseColumns {
public static final String TABLE_NAME = "entry";
public static final String COLUMN_NAME_TITLE = "title";
public static final String COLUMN_NAME_SUBTITLE = "subtitle";
}