I have a problem with making request using these both libraries. I wanted to get all queries from my table Table_events with .queryforall() but then I saw this thread and tried to make query with rawQuery but it offers only queryRaw(). The request looks like this:
private Dao<Table_Events, Integer> tEventDao;
public DAOManager(final DatabaseHelper databaseHelper)
{
this.tEventDao= GettEventDAO(databaseHelper);
}
public String[] Getall()
{
GenericRawResults<String[]> rawResults = null;
try
{
rawResults = tEventDao.queryRaw("select * from tableEvents");
}
catch (SQLException e)
{
e.printStackTrace();
}
return resultArray;
}
any ideas how make a query?
Your GettEventDAO function is returning an object that conforms to the Dao interface of ORMLite. You would need to make sure the implementation of ORMLite is able to interface with SQLCipher for Android which would typically return a Cursor representing the resultset of your query.
Related
We try to update sqlite_sequence with the following code.
WeNoteRoomDatabase weNoteRoomDatabase = WeNoteRoomDatabase.instance();
weNoteRoomDatabase.query(new SimpleSQLiteQuery("UPDATE sqlite_sequence SET seq = 0 WHERE name = 'attachment'"));
However, it has no effect at all. I exam the sqlite_sequence table content using SQLite browser. The counter is not reset to 0.
If we try to run the same query manually using SQLite browser on same SQLite file, it works just fine.
Our Room database is pretty straightforward.
#Database(
entities = {Attachment.class},
version = 6
)
public abstract class WeNoteRoomDatabase extends RoomDatabase {
private volatile static WeNoteRoomDatabase INSTANCE;
private static final String NAME = "wenote";
public abstract AttachmentDao attachmentDao();
public static WeNoteRoomDatabase instance() {
if (INSTANCE == null) {
synchronized (WeNoteRoomDatabase.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(
WeNoteApplication.instance(),
WeNoteRoomDatabase.class,
NAME
)
.build();
}
}
}
return INSTANCE;
}
}
Any idea what we had missed out?
Additional information : clearing sqlite_sequence is not working in android room
Room doesn't use SQLiteDatabase - but it uses SupportSQLiteDatabase, while it's source code states, that it delegates all calls to an implementation of {#link SQLiteDatabase}... I could even dig further - but I'm convinced, that this is a consistency feature and not a bug.
SQLiteDatabase.execSQL() still works fine, but with SupportSQLiteDatabase.execSQL() the same UPDATE or DELETE queries against internal tables have no effect and do not throw errors.
my MaintenanceHelper is available on GitHub. it is important that one initially lets Room create the database - then one can manipulate the internal tables with SQLiteDatabase.execSQL(). while researching I've came across annotation #SkipQueryVerification, which could possibly permit UPDATE or DELETE on table sqlite_sequence; I've only managed to perform a SELECT with Dao... which in general all hints for the internal tables are being treated as read-only, from the perspective of the publicly available API; all manipulation attempts are being silently ignored.
i think query is wrong, you should try below query
weNoteRoomDatabase.query(new SimpleSQLiteQuery("UPDATE sqlite_sequence SET seq = 0 WHERE name = attachment"));
I'm using room database version 2.2.5
Here I'm unable to execute this query using Room Dao structure, so make one simple class and access method as like this and I got successful outcomes so this one is tested result. I'm using RxJava and RxAndroid for same.
public class SqlHelper {
private static SqlHelper helper = null;
public static SqlHelper getInstance() {
if (helper == null) {
helper = new SqlHelper();
}
return helper;
}
public Completable resetSequence(Context context) {
return Completable.create(emitter -> {
try {
AppDatabase.getDatabase(context)
.getOpenHelper()
.getWritableDatabase()
.execSQL("DELETE FROM sqlite_sequence WHERE name='<YOUR_TABLE_NAME>'");
emitter.onComplete();
} catch (Exception e) {
emitter.onError(e);
}
});
}
}
Execute:
SqlHelper.getInstance()
.resetQuizSequence(context)
.subscribeOn(Schedulers.io()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(() -> {}, error -> {});
Table sql_sequence is not managed by Room, so you need to edit it using a SupportSQLiteDatabase.
Try this:
String sqlQuery = "DELETE FROM sqlite_sequence WHERE name='attachment'";
weNoteRoomDatabase().getOpenHelper().getWritableDatabase().execSQL(sqlQuery);
This works for me - Room 2.2.6
String sqlQuery = "DELETE FROM sqlite_sequence WHERE name='attachment'";
<YourDatabase>.getInstance(mContext).getOpenHelper().getWritableDatabase().execSQL(sqlQuery);
I'm using ORM Lite on a project , I decided to use the facility to make the persistence part of the Web service once and can reuse it on Android.
But I am suffering a lot because possou complex objects that have multiple ForeignCollectionField and Foreign object , and at the hour of perssistir temenda these data is a headache, because I have to enter one by one of their children , I think the idea of an ORM is make life easier , ie you have to persist the object and father and all the rest is done behind the scenes ...
Well, it is now too late to give up lite ORM , I wonder if there is a way to do what sitei above ..
I found a piece of code here
tried to implement but it seems not work , just keeps saving the parent object .
follows the function I'm trying to use , but do not know whether imports are correct because the code I found in the link above did not have this data
public int create(Object entity, Context context) throws IllegalArgumentException, IllegalAccessException, SQLException, SQLException {
try{
if (entity!=null){
// Class type of entity used for reflection
Class clazz = entity.getClass();
// Search declared fields and save child entities before saving parent.
for(Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
// Inspect annotations
Annotation[] annotations = field.getDeclaredAnnotations();
try{
for(Annotation annotation : annotations) {
// Only consider fields with the DatabaseField annotation
if(annotation instanceof DatabaseField) {
// Check for foreign attribute
DatabaseField databaseField = (DatabaseField)annotation;
if(databaseField.foreign()) {
// Check for instance of Entity
Object object = field.get(entity);
Dao gDao = getDatabase(context).getDao(object.getClass());
gDao.create(object);
}
}else if (annotation instanceof ForeignCollectionField){
Object object = field.get(entity);
for(Object obj : new ArrayList<Object>((Collection<?>)object)){
Class c = obj.getClass();
Dao gDao = getDatabase(context).getDao(obj.getClass());
gDao.create(obj);
}
}
}
}catch (NullPointerException e){
e.printStackTrace();
}
}
// Retrieve the common DAO for the entity class
Dao dao = getDatabase(context).getDao(entity.getClass());
// Persist the entity to the database
return dao.create(entity);
}else
return 0;
}finally {
if (database != null) {
OpenHelperManager.releaseHelper();
database = null;
}
}
}
Leveraging the same post, also need a colução to delete cascade, imagine a situation where I have the following tables:
Company > Category> person> contact> Phone and email
Deleting and now I do as described in the documentation:
public int deleteCascade(Prefeitura prefeitura, Context context){
try{
Dao<Prefeitura, Integer> dao = getDatabase(context).getDao(Prefeitura.class);
DeleteBuilder db = dao.deleteBuilder();
db.where().eq("prefeitura_id", prefeitura.getId());
dao.delete(db.prepare());
// then call the super to delete the city
return dao.delete(prefeitura);
}catch (SQLException e){
e.printStackTrace();
}
return 0;
}
But the objects that are not directly linked the company would still be in the database, how could I do?
But without hacks, I want a clean code ...
I know ORM Lite really is lite, but one that saves the children create and delete cascade is essential for any ORM, hopefully for the next versions it is implemented, it is regrettable not have these features, for simple projects is very good, but in a complex project because a lot of headaches, I'm feeling on the skin.
Any help is welcome!
I need to delete a record from ORMLite Database I can delete a record by id using as below
#Override
public void Delete(int id) throws SQLException {
this.dao.deleteById(id);
}
but what if I have to delete a record from same table not by id but by name or any other field
I want something like
public void Deletefromcanteen(String name,MealType mealtype) {
this.dao.deletebyName(name);
}
what query should i write using querybuilder to delete a record where name = name and mealtype = say (lunch)
I tried something like this in my databasehelper class
public void deletefromcanteen(int id, String mealtype) {
try {
Dao<CanteenLog, Integer> canteenDao = getCanteen();
DeleteBuilder<CanteenLog, Integer> deleteBuilder = canteenDao
.deleteBuilder();
deleteBuilder.where().eq("user_id", id).and().eq("meal", mealtype);
canteenDao.delete(deleteBuilder.prepare());
} catch (Exception e) {
...
}
}
deleteBuilder.where().eq("FIELD_NAME", arg);
deleteBuilder.delete();
Update:
For example :
//Get helper
DatabaseHelper helper = OpenHelperManager.getHelper(App.getContext(), DatabaseHelper.class);
//get dao
Dao dao = helper.getDao(YOUR_CLASS.class);
//delete elements from table in field by arg
DeleteBuilder<CanteenLog, Integer> deleteBuilder = dao.deleteBuilder();
deleteBuilder.where().eq("FIELD_NAME", arg);
deleteBuilder.delete();
Good luck!
To save building a query, you can do a select to find the ID, then do a delete by ID. Thsi will be straightforward if you already have the select query set up for this table.
It can be done also like that
DatabaseHelper.getInstance().getDao(YourObject.class).delete(yourObjectInstance);
If you are using Kotlin, you will need to do something like this instead since the type inference is not currently working correctly for the fluent syntax:
val deleteBuilder = dao.deleteBuilder()
val where = deleteBuilder.where().eq("address", address)
deleteBuilder.setWhere(where)
deleteBuilder.delete()
If you already have an instance of the object (or object list) you want to delete, just do :
//Get helper
DatabaseHelper helper =
OpenHelperManager.getHelper(App.getContext(), DatabaseHelper.class);
// delete 'em !
helper.getDao(YourObject.class).delete(yourObjectInstance);
If you don't have the instance to delete or you want to do it SQL way(!):
//Get helper
DatabaseHelper helper =
OpenHelperManager.getHelper(App.getContext(), DatabaseHelper.class);
//get dao
Dao dao = helper.getDao(YOUR_CLASS.class);
//delete elements from table in field by arg
DeleteBuilder<CanteenLog, Integer> deleteBuilder = dao.deleteBuilder();
deleteBuilder.where().eq("FIELD_NAME", "FIELD_VALUE");
deleteBuilder.delete();
If you need a more complicated Where logic, then use deleteBuilder.where().or() or deleteBuilder.where().and() to add more constraints.
I am new to this, please help me.
I am trying to use ormlite like(column name,value) function, but this is not working for me. But when I test full text it is working like "eq" function.
My Code is,
try {
QueryBuilder<MakeDTO, Integer> qb = makeDao.queryBuilder();
qb.where().like("madeCompany", filterKey);
PreparedQuery<MakeDTO> pq = qb.prepare();
return makeDao.query(pq);
} catch (SQLException e) {
throw new AppException(e);
}
Thanks.
An old question, but something I just solved (ORMLite's documentation isn't that clear). you need to wrap your query parameter in "%"'s in order to tell ORMLite which side of your query string can match any number of characters.
For example, if you want your query to match any madeCompany that contains your string use the following:
try {
QueryBuilder<MakeDTO, Integer> qb = makeDao.queryBuilder();
qb.where().like("madeCompany", "%"+filterKey+"%");
PreparedQuery<MakeDTO> pq = qb.prepare();
return makeDao.query(pq);
} catch (SQLException e) {
throw new AppException(e);
}
Pretty simple, you're asking it to be exactly the string 'madeCompany', if you want to do partial matching you need to use the % wildcard etc.
public Where<T,ID> like(java.lang.String columnName,
java.lang.Object value)
throws java.sql.SQLException
Add a LIKE clause so the column must mach the value using '%' patterns.
Throws:
java.sql.SQLException
Where.like(java.lang.String, java.lang.Object)
The answers above can resolved the like query problem, but has SQL injection risk. If the value of 'filterKey' is ', it will cause SQLException, because the SQL will be SELECT * FROM XXX WHERE xxx LIKE '%'%'. You could use SelectArg to avoid, example for this case:
try {
String keyword = "%"+filterKey+"%";
SelectArg selectArg = new SelectArg();
QueryBuilder<MakeDTO, Integer> qb = makeDao.queryBuilder();
qb.where().like("madeCompany", selectArg);
PreparedQuery<MakeDTO> pq = qb.prepare();
selectArg.setValue(keyword);
return makeDao.query(pq);
} catch (SQLException e) {
throw new AppException(e);
}
Reference: http://ormlite.com/javadoc/ormlite-core/doc-files/ormlite_3.html#index-select-arguments
The goal: refresh database from XML data
The process:
Start transaction
Delete all existing rows from the tables
Per each main element of parsed XML insert row into main table and get PK
Per each child of the main element insert record into 2nd table providing FK from the previous step
Commit transaction
Pretty standard stuff as far as db operations. The problem is that CRUD operations are not done within ContentProvider but rather using ContentResolver so the insert for example looks like resolver.insert(CONTENT_URI, contentValues). The ContentResolver API doesn't seem to have anything pertained to transaction and I cannot use bulkInsert since I'm inserting in 2 tables intermittently (plus I want to have delete inside the transaction as well).
I was thinking of registering my customized ContentProvider as listener by using registerContentObserver but since ContentResolver#acquireProvider methods are hidden how do I obtain the right reference?
Am I out of luck?
I've seen that in the source code of Google I/O application, they override ContentProvider's applyBatch() method and use transactions inside of it. So, you create a batch of ContentProviderOperation s and then call getContentResolver().applyBatch(uri_authority, batch).
I'm planning to use this approach to see how it works. I'm curious if anyone else has tried it.
It is possible to do transaction based multi table inserts rather cleanly since Android 2.1 by using ContentProviderOperation, as mentioned by kaciula.
When you build the ContentProviderOperation object, you can call .withValueBackReference(fieldName, refNr). When the operation is applied using applyBatch, the result is that the ContentValues object that is supplied with the insert() call will have an integer injected. The integer will be keyed with the fieldName String, and its value is retrieved from the ContentProviderResult of a previously applied ContentProviderOperation, indexed by refNr.
Please refer to the code sample below. In the sample, a row is inserted in table1, and the resulting ID (in this case "1") is then used as a value when inserting the row in table 2. For brevity, the ContentProvider is not connected to a database. In the ContentProvider, there are printouts where it would be suitable to add the transaction handling.
public class BatchTestActivity extends Activity {
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ArrayList<ContentProviderOperation> list = new
ArrayList<ContentProviderOperation>();
list.add(ContentProviderOperation.
newInsert(BatchContentProvider.FIRST_URI).build());
ContentValues cv = new ContentValues();
cv.put("name", "second_name");
cv.put("refId", 23);
// In this example, "refId" in the contentValues will be overwritten by
// the result from the first insert operation, indexed by 0
list.add(ContentProviderOperation.
newInsert(BatchContentProvider.SECOND_URI).
withValues(cv).withValueBackReference("refId", 0).build());
try {
getContentResolver().applyBatch(
BatchContentProvider.AUTHORITY, list);
} catch (RemoteException e) {
e.printStackTrace();
} catch (OperationApplicationException e) {
e.printStackTrace();
}
}
}
public class BatchContentProvider extends ContentProvider {
private static final String SCHEME = "content://";
public static final String AUTHORITY = "com.test.batch";
public static final Uri FIRST_URI =
Uri.parse(SCHEME + AUTHORITY + "/" + "table1");
public static final Uri SECOND_URI =
Uri.parse(SCHEME + AUTHORITY + "/" + "table2");
public ContentProviderResult[] applyBatch(
ArrayList<ContentProviderOperation> operations)
throws OperationApplicationException {
System.out.println("starting transaction");
ContentProviderResult[] result;
try {
result = super.applyBatch(operations);
} catch (OperationApplicationException e) {
System.out.println("aborting transaction");
throw e;
}
System.out.println("ending transaction");
return result;
}
public Uri insert(Uri uri, ContentValues values) {
// this printout will have a proper value when
// the second operation is applied
System.out.println("" + values);
return ContentUris.withAppendedId(uri, 1);
}
// other overrides omitted for brevity
}
All right - so this does not dingle aimlessly: the only way I can think of is to code startTransaction and endTransaction as URL-based query requests. Something like ContentResolver.query(START_TRANSACTION, null, null, null, null). Then in ContentProvider#query based on the registered URL call start or end transaction
You can get the implementation of the content provider object itself (if in the same process, hint: you can control the provider's process with multiprocess="true" or process="" http://developer.android.com/guide/topics/manifest/provider-element.html) using ContentProviderClient.getLocalContentProvider () which can be casted to your provider implementation which can provide extra functionality like a reset() that closes and deletes the database and you can also return a custom Transaction class instance with save() and close() methods.
public class Transaction {
protected Transaction (SQLiteDatabase database) {
this.database = database;
database.beginTransaction ();
}
public void save () {
this.database.setTransactionSuccessful ();
}
public void close () {
this.database.endTransaction ();
}
private SQLiteDatabase database;
}
public Transaction createTransaction () {
return new Transaction (this.dbHelper.getWritableDatabase ());
}
Then:
ContentProviderClient client = getContentResolver ().acquireContentProviderClient (Contract.authorityLocal);
Transaction tx = ((LocalContentProvider) client.getLocalContentProvider ()).createTransaction ();