How to access one class database in another class? - android

I created a database in my class like
public final String CRAZY_ALARM_DB_NAME = "CrazyDb";
public final String CRAZY_ALARM_TABLE_NAME = "CrazyTable";
alarmDB = this.openOrCreateDatabase(
CRAZY_ALARM_DB_NAME, MODE_PRIVATE, null
);
alarmDB.execSQL("CREATE TABLE IF NOT EXISTS "
+ CRAZY_ALARM_TABLE_NAME
+" (REQ_CODE INT(3),DAY INT(3),HOUR INT(3)"
+",MINUTE INT(3),COUNT INT(3),REPEAT INT(3)"
+",DAYS VARCHAR2(100),SUN INT(3),MON INT(3),"
+"TUE INT(3),WED INT(3),THU INT(3),FRI INT(3),"
+"SAT INT(3));"
);
cr = alarmDB.rawQuery("SELECT * FROM "
+CRAZY_ALARM_TABLE_NAME, null
);
so i want to use this database in another class. I am also do the same thing ,i wrote "openorcreate "code in another class and also cursor..
but it gave an exception like no such table while compiling ... at cursor line..
please help me.

You should use an SQLiteOpenHelper-class to access and maintain your Database.
If you do so, you can (in whatever class you like) use the following lines to get a read or writable database:
YourSQliteOpenHelper db_con = new YourSQliteOpenHelper(getApplicationContext());
// Readable:
SQLiteDatabase db = db_con.getReadableDatabase();
// Writeable:
SQLiteDatabase db = db_con.getWritableDatabase();
A tutorial on how to use the SQLiteOpenHelper can be found here.

The best you could do is to have a database helper where you could have all these calls and which could be available and accessible by all your activities.
Moreover, you should remove and install again your app in order to be able to create the table. I have this problem sometimes.

Related

"Cannot add a NOT NULL column with default value NULL" with Requery after automatic DB migration

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;
}

Android - Cursor not properly working

I have an app that inserts data into a database with 2 tables (project and alvara)
The insertion method for the second table depends on what type the first table gets. (1 or 2) for resumed idea.
This is a method that I made for looking into the second table with cursor. If it finds, it sets in setters from alvara_db class. And later on, I use getters to show info on textviews in another activity. The issue is that it's not setting info at all. Is anything wrong in my Cursor?
Thanks in advance!
public ArrayList<alvara_db> getAlvaras(){
SQLiteDatabase db = this.getReadableDatabase();
ArrayList<alvara_db> projects = new ArrayList<>();
String[] project = new String[]{String.valueOf(tipoprojetoid)};
Cursor cur = db.rawQuery("SELECT placa, proj_exec, resp_tec, rtnum, parecer FROM alvara WHERE projetoid = ?", project);
cur.moveToFirst();
alvara_db alvaras = new alvara_db();
alvaras.setPlaca(cur.getInt(cur.getColumnIndex("placa")));
alvaras.setProj_exec(cur.getInt(cur.getColumnIndex("proj_exec")));
alvaras.setResp_tec(cur.getString(cur.getColumnIndex("resp_tec")));
alvaras.setRtnum(cur.getInt(cur.getColumnIndex("rtnum")));
alvaras.setParecer(cur.getString(cur.getColumnIndex("parecer")));
projects.add(alvaras);
return projects;
}
Fragment where I call getAlvaras method:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.detalhes_projeto_alvara);
db.getAlvaras();
placa = alvaras.getPlaca();
resp_tec = alvaras.getResp_tec();
proj_exec = alvaras.getProj_exec();
rtnum = alvaras.getRtnum();
}
You are not using the returned value from db.getAlvaras().
Instead the alvaras variable in your second snippet is something that is likely not initialized - the code you posted does not show that exactly.
(In addition, you might want to check the return value of moveToFirst() in case the query matches no rows, and add a do-while loop to retrieve more than one row.)

How to write Robolectric (2.3) test using database

Due to last release of Robolectic to version 2.3, it's written that (https://github.com/robolectric/robolectric/releases):
Robolectric now uses a real implementation of SQLite instead of a collection of shadows and fakes. Tests can now be written to verify real database behavior.
I haven't found any "How to" documentation.
I'd like to know how should I implement test on e.g. Activity using SQLiteDatabase query. Where should I put .db file so a test uses it.
You will need to put the .db file under src/test/resources/ folder.
For example, sample.db
Then in your unit test setUp() call:
#Before
public void setUp() throws Exception {
String filePath = getClass().getResource("/sample.db").toURI().getPath();
SQLiteDatabase db = SQLiteDatabase.openDatabase(
(new File(filePath)).getAbsolutePath(),
null,
SQLiteDatabase.OPEN_READWRITE);
// perform any db operations you want here
}
Here is an example how to test database, oprations.
// just a wrapper for the content values map
Agenda agenda = new Agenda();
agenda.setName("MyAgenda");
agenda.setDate("current date");
long rowId = agendaManager.insert(agenda); // the guy who makes database operations
Cursor query = context.getContentResolver().query(AgendaProvider.AGENDA_CONTENT_URI, null, null, null, null);
assertThat(query.getCount()).isEqualTo(1);
query.moveToNext();
Agenda dbAgenda = new Agenda(query);
assertThat(dbAgenda.getRowId()).isPositive();
assertThat(dbAgenda.getRowId()).isEqualTo(rowId);
assertThat(dbAgenda.getName()).isEqualTo(agenda.getName());
assertThat(dbAgenda.getDate()).isEqualTo(agenda.getDate());
An more detailed example may be found here https://github.com/nenick/android-gradle-template/blob/master/UnitTestsRobolectric/src/test/java/com/example/managers/AgendaManagerTest.java

How to clean/delete greenDao database

Currently I'm doing it like this:
DaoMaster.dropAllTables(getDb(), true);
DaoMaster.createAllTables(getDb(), true);
but then, when I'm trying to add entity to the database, I'm getting crash log saying that this table isn't exist
Edit1:
I know that it happens because the db is locked and tables wasn't created yet. So I'm reducing this problem to the problem - how to know if the tables are locked in grrenDao/Sqlite?
How about using something like this for each table?
daoSession.getSometableDao().deleteAll();
Until now, I don't worry if tables are locked or not; in my case, i do the following and it works:
First, when App.onCreate executes, I make the standard initializations.
T.devOpenHelper= new DaoMaster.DevOpenHelper(context, "mydatabase", null);
T.sqLiteDatabase= T.devOpenHelper.getWritableDatabase();
T.daoMaster= new DaoMaster(T.sqLiteDatabase);
T.daoSession= T.daoMaster.newSession();
T.dao_myEntity= T.daoSession.getMyEntityDao();
In some moment in the future I drop and recreate all tables, just like you:
T.daoMaster.dropAllTables(T.sqLiteDatabase, true);
T.daoMaster.createAllTables(T.sqLiteDatabase, true);
But in my case, then I can immediately insert a new entity:
MyEntity e= new MyEntity();
e.setId_ticket(1L);
e.setDescription("wololo");
long id= T.dao_myEntity.insert(e);
Log.d(G.tag, "T.erase_all: id: " + id); // prints "T.erase_all: id: 1"
I hope it helps.
public static void clearDatabase(Context context) {
DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(
context.getApplicationContext(), Constants.SQL_DB_NAME, null);
SQLiteDatabase db = devOpenHelper.getWritableDatabase();
devOpenHelper.onUpgrade(db,0,0);
}
For now it can be done like that:
for (AbstractDao abstractDao : mDaoSession.getAllDaos()){
abstractDao.deleteAll();
}
I upgraded the schemaVersion in build.gradle to pass through this error
Try this one:
QueryBuilder<cart> qb = SQLConfig.cartDao.queryBuilder();
List<cart> mUpadateData = qb.where(cartDao.Properties.Product_sku.eq(skuApi)).list();
SQLConfig.cartDao.deleteInTx(mUpadateData);

ORMLite joins queries and Order by

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.

Categories

Resources