I have a SQLite table of this tipe
Table Vehicles:
CATEGORY COUNTRY ID NAME EMAIL
A GE 1 BMW sample1#salple.it
A GE 2 Lamborghini sample2#salple.it
B GE 3 BMW sample3#salple.it
I want to select all the entries that have a specified name or a specified category and pass all the parameters how each row in a constructor
Vehicle(String category, String country, int id, String name, String email)
I have implemented this adapter using some tutorials:
public class TestAdapter
{
protected static final String TAG = "DataAdapter";
private final Context mContext;
private SQLiteDatabase mDb;
private DataBaseHelper mDbHelper;
public TestAdapter(Context context)
{
this.mContext = context;
mDbHelper = new DataBaseHelper(mContext);
}
public TestAdapter createDatabase() throws SQLException
{
try
{
mDbHelper.createDataBase();
}
catch (IOException mIOException)
{
Log.e(TAG, mIOException.toString() + " UnableToCreateDatabase");
throw new Error("UnableToCreateDatabase");
}
return this;
}
public TestAdapter open() throws SQLException
{
try
{
mDbHelper.openDataBase();
mDbHelper.close();
mDb = mDbHelper.getReadableDatabase();
}
catch (SQLException mSQLException)
{
Log.e(TAG, "open >>"+ mSQLException.toString());
throw mSQLException;
}
return this;
}
public void close()
{
mDbHelper.close();
}
public boolean SaveVehicles(String category , String country, String id, String name, String email)
{
try
{
ContentValues cv = new ContentValues();
cv.put("Category", category);
cv.put("Country", country);
cv.put("id", id);
cv.put("Name", name);
cv.put("Email", email);
mDb.insert("Vehicles", null, cv);
Log.d("SaveVehicles", "informationsaved");
return true;
}
catch(Exception ex)
{
Log.d("SaveVehicles", ex.toString());
return false;
}
}
}
But I don't know how I could implement the various get methods that I need, to meet a solution to my problem.
Creating an object from a SQL query would look something like this
/**
* #return Returns a list of all objects.
*/
public ArrayList<Object> getAllObjects()
{
// Select All Query
String selectQuery = "SELECT * FROM SOME_TABLE";
// Get the isntance of the database
SQLiteDatabase db = this.getWritableDatabase();
//get the cursor you're going to use
Cursor cursor = db.rawQuery(selectQuery, null);
//this is optional - if you want to return one object
//you don't need a list
ArrayList<Object> objectList = new ArrayList<Object>();
//you should always use the try catch statement incase
//something goes wrong when trying to read the data
try
{
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
//the .getString(int x) method of the cursor returns the column
//of the table your query returned
Object object= new Object(Integer.parseInt(cursor.getString(0)),
Integer.parseInt(cursor.getString(1)),
Integer.parseInt(cursor.getString(2)),
cursor.getString(3),
cursor.getString(4),
cursor.getString(5),
Boolean.parseBoolean(cursor.getString(6))
);
// Adding contact to list
objectList.add(object);
} while (cursor.moveToNext());
}
}
catch (SQLiteException e)
{
Log.d("SQL Error", e.getMessage());
return null;
}
finally
{
//release all your resources
cursor.close();
db.close();
}
return objectList;
}
The code above assumes you have some table in your database named "SOME_TABLE" and that you have an object that takes 7 parameters but you should be able to alter the snippet to make it work for you.
You need to query your database for the data, and then iterate through the returned cursor to pull out the data you need and put it into strings to feed into your constructor.
The query would look something like this (using the info you provided and the query method):
public Cursor fetchList(String category) {
return mDb.query("Vehicles", new String[] { "CATEGORY", "COUNTRY", "ID", "NAME", "EMAIL" }, "Category =" + category,
null, null, null, null);
}
Note that this is a basic query and subject to SQL injection attacks, It should be parameterized to make it less vulnerable, unless you are not going to allow the user to type in the category and rather have them pick from a list you provide.
Anyway, that would return your data in a cursor, with one row for each record that matched the search parameters. From there, you would need to iterate through the returned cursor and pull the data out of it and into strings you can use.
Related
I am saving data to an SQLite Database. It's taking a while for small amounts of data to be saved. I'm using: beginTransaction();
setTransactionSuccessful();, endTransaction(); etc but it doesn't improve performance. I'm considering switching to RealmDB if I can't improve this. Does anyone have any tips? Cheers
public enum DbSingleton {
INSTANCE;
private DatabaseHandler db;
public Context context;
private DatabaseHandler getDatabaseHandler(Context context) {
if (db != null) {
return db;
} else {
if (MainActivity.mainActivity == null) {
SQLiteDatabase.loadLibs(context);
return db = new DatabaseHandler(context); //make static context field in area this is used. e.g. main
} else {
return db = new DatabaseHandler(MainActivity.mainActivity);
}
}
}
//will provide one sample for reference now
public void insert(Context context, String table, ContentValues values) {
SQLiteDatabase.loadLibs(MainActivity.mainActivity);
//note this line
SQLiteDatabase sql = getDatabaseHandler(context).getWritableDatabase(DatabaseHandler.DB_PASSWD);
try {
sql.beginTransaction();
sql.insert(table, null, values);
// Log.i("Values being sent to db", values.toString());
sql.setTransactionSuccessful();
sql.endTransaction();
} catch (SQLiteException ex) {
Log.e("SQL EXCEPTION", ex.toString());
} finally {
sql.close();
}
}
public Cursor select(Context context, String statement, String[] selectArgs) {
SQLiteDatabase sql = getDatabaseHandler(context).getReadableDatabase(DatabaseHandler.DB_PASSWD);
if (selectArgs == null) {
return sql.rawQuery(statement, null);
} else {
return sql.rawQuery(statement, selectArgs);
}
}
public int Update(Context context, String table, ContentValues values, String where, String[] whereArgs) {
SQLiteDatabase sql = getDatabaseHandler(context).getWritableDatabase(DatabaseHandler.DB_PASSWD);
int count = -1;
try {
sql.beginTransaction();
count = sql.update(table, values, where, whereArgs);
sql.setTransactionSuccessful();
sql.endTransaction();
} catch (SQLiteException ex) {
Log.e("SQL EXCEPTION", ex.toString());
}
if (count == 0) count = -1;
return count;
}
public void Drop(Context context, String table) {
SQLiteDatabase sql = getDatabaseHandler(context).getWritableDatabase(DatabaseHandler.DB_PASSWD);
sql.execSQL("DROP TABLE IF EXISTS " + table);
}
public void Create(Context context, String table) {
SQLiteDatabase sql = getDatabaseHandler(context).getWritableDatabase(DatabaseHandler.DB_PASSWD);
sql.beginTransaction();
sql.execSQL(table);
sql.setTransactionSuccessful();
sql.endTransaction();
}
Wrapping your inserts in beginTransaction() and endTransaction() is only saving time when you do multiple inserts.
So always save your data to one table at once using the following format, this greatly improves performance:
ArrayList<String> itemsToInsert; //an array of strings you want to insert
db.beginTransaction();
ContentValues values = new ContentValues(1);
for (int i = 0; i < itemsToInsert.size(); i++) {
values.put('field', itemsToInsert.get(i));
db.insert(table, null, values);
}
db.setTransactionSuccessful();
db.endTransaction();
In addition, for selecting from a table, query() is performing slightly better than rawQuery(), but the difference is small.
Als check this article for more background information about SqlLite Performance:
sqlite-insertions
Android provides a new library as part of the architecture components called Room.
official doc says:
The Room persistence library provides an abstraction layer over SQLite
to allow for more robust database access while harnessing the full
power of SQLite.
Room Persistence Library
Save data in a local database using Room
More:
You can use the room with another awesome library (Paging Library) to handle paging and huge data sets
Paging library
The application am working on will initially have one database with a table, say tbl_usr which will have only one record. Basically we are trying to keep one user per device. When the user logs in from the device with an auth code, his details will be fetched from server and stored in database. Next time if he tries to enter different auth code, which is valid but is not in table then he will not be allowed to proceed. Below is a common DBHelper class.
But whatever approach am trying, I am getting databaselocked exception, when tried for the 2nd time login. I've referred various links where in it was suggested to use different instance of database within method, but still it comes with error. Below is my Helper class
public class DBaseHelper extends SQLiteOpenHelper {
private static String CREATE_TABLE;
private static final String DATABASE_NAME="IPDB";
private static String UserMessage="";
private int tableType=0;
private ContentValues cValues;
private Cursor cursor;
public enum TableTypes{
Table1
};
public DBaseHelper(Context context){
super(context,context.getExternalFilesDir(null).getAbsolutePath()+"/"+DATABASE_NAME,null,1);
}
#Override
public void onCreate(SQLiteDatabase db){
TableTypes tableTypes=TableTypes.values()[tableType];
switch (tableTypes){
case Table1:
CREATE_TABLE="CREATE TABLE IF NOT EXISTS tbl_usr....";
break;
default:
break;
}
db.execSQL(CREATE_TABLE);
db.close();
System.out
.println("onCreate Method Done.");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
/*db.execSQL("DROP TABLE IF EXISTS "+LOGIN_TABLE);*/
onCreate(db);
}
/*this is the method which gets called from other class Like*/
/*helper.insertRecord(tableParams);*/
public HashMap<String,String> insertRecord(HashMap<String,String> dbaseParams){
HashMap<String,String> response=new HashMap<String,String>();
tableType=Integer.parseInt(dbaseParams.get("tableType"));
cValues = new ContentValues();
String TableName="";
TableTypes tableTypes=TableTypes.values()[tableType];
switch (tableTypes){
case Table1:
String AuthCode=dbParams.get("AuthCode");
/*if user exists then check if its the same user*/
if( CheckUserRecordExists(AuthCode) && empty(UserMessage) ){
response.put("isSuccess","true");
return response;
}
else {
if (!empty(UserMessage)) {
response.put("isSuccess", "false");
response.put("message",UserMessage);
return response;
}
/*add new user
Fill cValues declared above*/
TableName = "Table1";
}
break;
default:
break;
}
SQLiteDatabase dataBase = getWritableDatabase();
/*insert data into database*/
try {
dataBase.beginTransaction();
long rowID = dataBase.insertOrThrow(TableName, null, cValues);
dataBase.setTransactionSuccessful();
}
catch(Exception ex){
ex.printStackTrace();
}
finally {
dataBase.close();
}
response.put("isSuccess", "true");
return response;
}
private boolean CheckUserRecordExists(String authCode){
UserMessage="";
SQLiteDatabase dataBase=getReadableDatabase();
/*Exception here when comes for 2nd time after new installation*/
cursor = dataBase.query("Table1", new String[]{"COUNT(*)"}, null, null, null, null, null);
cursor.moveToFirst();
int iCount=cursor.getInt(0);
/*check if any record exist*/
if(iCount>0){
dataBase.close();
if(!cursor.isClosed()) cursor.close();
/*check if the code entered matches with the record existing*/
if(!CheckIsDataAlreadyInDBorNot("Table1","Auth_Code",authCode))
{
UserMessage="Invalid login!";
return false;
}
else return true;
}
else{
dataBase.close();
if(!cursor.isClosed()) cursor.close();
return false;
}
}
private boolean CheckIsDataAlreadyInDBorNot( String TableName,
String dbfield, String fieldValue) {
/*checking if user is same user*/
SQLiteDatabase dataBase=getReadableDatabase();
String[] columns = { dbfield };
String selection = dbfield + " =?";
String[] selectionArgs = { fieldValue };
String limit = "1";
Cursor cursor = dataBase.query(TableName, columns, selection, selectionArgs, null, null, null, limit);
boolean exists = (cursor.getCount() > 0);
cursor.close();
dataBase.close();
return exists;
}
public static boolean empty( final String s ) {
return s == null || s.trim().isEmpty();
}
}
I know its a huge code, but logic is simple. But the problem is database lock. Could someone let me know how I can make sure that database is always in valid state on each operation?
You have beginTransaction() but no matching calls to endTransaction(). An ongoing transaction keeps the database in a locked state and also keeps the internal reference count nonzero, so close() does not yet actually close the database.
The conventional pattern for transactional operations is
db.beginTransaction();
try {
// db operations that can throw
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
Also in your onCreate() you should not be closing the database since you don't own it.
I have a custom List which holds information stored from a online mysql database. I now want to put this List into a sqlite internal database. The table has already been created in the database. I also have a databasehelper class which is working fine.
All the list information is stored in FoodInfoModel class which is made of get and set properties.
Do I create a method in the databasehelper class to insert the whole list at once? not sure how to go about it.
Current Method in databasehelper
public void addDiet(FoodInfoModel foodinfomodel) {
SQLiteDatabase db = getReadableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_DIET_ID, foodinfomodel.getDietID());
values.put(KEY_DAY, foodinfomodel.getDay());
values.put(KEY_QTY, foodinfomodel.getQty());
values.put(KEY_TIME_FOOD, foodinfomodel.getTime());
values.put(KEY_ITEM_FOOD, foodinfomodel.getItem());
values.put(KEY_MEASURE, foodinfomodel.getMeasure());
// Inserting Row
db.insert("my_diet", null, values);
db.close(); //
}
Function to set List and Adapter
public void onFetchComplete(List<FoodInfoModel> data) {
this.data = data;
System.out.println("data is " + data);
if(dialog != null) dialog.dismiss();
// create new adapter
adapter = new DietAdapterNew(this, data);
// set the adapter to list
setListViewHeightBasedOnChildren(listview);
listview.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
How do i add that data list to the internal sqlite db?
Thanks!
You basically need one more method.
public void addDiet(List<FoodInfoModel> foodinfomodels) {
SQLiteDatabase db = getReadableDatabase();
for( FoodInfoModel foodinfomodel : foodinfomodels ){
ContentValues values = new ContentValues();
values.put(KEY_DIET_ID, foodinfomodel.getDietID());
values.put(KEY_DAY, foodinfomodel.getDay());
values.put(KEY_QTY, foodinfomodel.getQty());
values.put(KEY_TIME_FOOD, foodinfomodel.getTime());
values.put(KEY_ITEM_FOOD, foodinfomodel.getItem());
values.put(KEY_MEASURE, foodinfomodel.getMeasure());
// Inserting Row
db.insert("my_diet", null, values);
}
db.close(); //
}
Yes, you have to create this kind of methods in DatabaseHelper class
public class DatabaseHandler extends SQLiteOpenHelper {
public void insertFoodInfo(ChatBase chat) {
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_DIET_ID, foodinfomodel.getDietID());
values.put(KEY_DAY, foodinfomodel.getDay());
values.put(KEY_QTY, foodinfomodel.getQty());
values.put(KEY_TIME_FOOD, foodinfomodel.getTime());
values.put(KEY_ITEM_FOOD, foodinfomodel.getItem());
values.put(KEY_MEASURE, foodinfomodel.getMeasure());
db.insert("my_diet", null, values);
db.close();
}
public void updateFoodInfo(FoodInfoModel model) {
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_DIET_ID, foodinfomodel.getDietID());
values.put(KEY_DAY, foodinfomodel.getDay());
values.put(KEY_QTY, foodinfomodel.getQty());
values.put(KEY_TIME_FOOD, foodinfomodel.getTime());
values.put(KEY_ITEM_FOOD, foodinfomodel.getItem());
values.put(KEY_MEASURE, foodinfomodel.getMeasure());
db.update("my_diet", values, KEY_DIET_ID + "=" + model.getId(),null);
db.close();
}
}
and then update or insert each FoodInfoModel inside the loop
And for bulk insert can use this code
db.beginTransaction();
try {
...
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
What you should create is a separate class with public static functions that process the CRUD (Create, Read, Update and Delete) functions associated with the SQL transactions.
Example (SQLcrud.java):
public static boolean insertObject(SQLdatabase localDB, Object insertObject)
{
// Test if things are not null and that the DB is open and writable.
// Insert the object
// If insert successful, return TRUE.
// If anything wrong or insert not successful return FALSE (or int indicating what went wrong.
}
Actual Example:
public static boolean insertLocalAdr(SQLiteDatabase db, PersonAddress adr, boolean deleteCurrent, boolean transaction)
throws SQLFunctionFailed {
if(db != null && adr != null)
{
try
{
// If the connection is open and writable.
SQLiteGeneral.openAndWritable(db);
if(deleteCurrent)
{
deleteLocalAdr(db, transaction);
}
String sqlStmt = GeneralSQLfunctions.getUserAdrInsert(
adr,
PersonAddress.ADR_TABLE_NAME,
GeneralSQLfunctions.databaseType.SQLITE);
return StmtExecution(db, sqlStmt, transaction);
}
catch (SQLException e)
{
e.printStackTrace();
throw new SQLFunctionFailed(e.getMessage());
}
}
else
{
throw new SQLFunctionFailed("Given DB or Adr was NULL! FATAL ERROR!");
}
}
Note: GeneralSQLfunctions.getUserAdrInsert just gets a simple formatted INSERT statement and StmtExecution simply executes the statement on the SQL DB. They are there for simplification. SQLiteGeneral.openAndWritable(db) throws a (custom) SQLFunctionFailed exception so the function fails and does not proceed.
While iterating over each list items, you can start a new AsyncTask or Thread to to make it faster.
I had created sqlite database,What I want to do is that when user enter value then i want to check that the value is already exist if value already exist then UPDATE otherwise INSERT that value, I had tried is...
public long insertDataCat(String id,String cat)
{
try {
SQLiteDatabase db;
db = this.getWritableDatabase(); // Write Data
ContentValues Val = new ContentValues();
Val.put("IDD", id);
Val.put("Categoryy", cat);
long rows = db.insert(TABLE_CATEGARY_MASTER, null, Val);
db.close();
return rows; // return rows inserted.
} catch (Exception e) {
return -1;
}
}
First you get the cursor count of table if any record found in the table mean it's return the cursor count 1 otherwise return zero.If cursor count one mean you perform UPDATE Operation otherwise Perform Insert Operation.
public long insertDataCat(String id,String cat)
{
try {
SQLiteDatabase db;
db = this.getWritableDatabase(); // Write Data
ContentValues Val = new ContentValues();
Val.put("IDD", id);
Val.put("Categoryy", cat);
String selectQuery = "select * from TABLE_CATEGARY_MASTER";
Cursor cursor = db.rawQuery(selectQuery, null);`
if(cursor.getCount()==1)
{
//execute update query here
long updaterow=db.update(TABLE_CATEGARY_MASTER,val);
return updaterow; // return rows inserted.
}
else
{
//Perform the insert query
long rows = db.insert(TABLE_CATEGARY_MASTER, null, Val);
return rows; // return rows inserted.
}
db.close();
} catch (Exception e) {
return -1;
}
}
I'm trying to load an sqlite table as an arraylist so that i can use the data in it. I'm not too sure about the sqlite queries but i already have a class built to manipulate the strings as is, which is what i'm more comfortable with. I can load an individual row but i'm not sure how to get the whole table as an arraylist.
I have the following method in my main method
public void ShowCNData()
{
TestAdapter mDbHelper = new TestAdapter(this);
mDbHelper.createDatabase();
mDbHelper.open();
String allData = mDbHelper.getCYData().get(1)[1];
thing.setText(allData);
mDbHelper.close();
}
and the following method in my dbAdapter/Helper class
public ArrayList<String[]> getCYData()
{
ArrayList<String[]> CYData = new ArrayList<String[]>();
try
{
String sql ="SELECT * FROM cnYears ";
Cursor mCur = null;
do
{
mCur = mDb.rawQuery(sql, null);
CYData.add(new String[] {mCur.getString(0),mCur.getString(1),mCur.getString(2),mCur.getString(3),mCur.getString(4)});
}
while (mCur.moveToNext());
return CYData;
}
catch (SQLException mSQLException)
{
Log.e(TAG, "getTestData >>"+ mSQLException.toString());
throw mSQLException;
}
}
How do i load the data into my ArrayList?
Without actual log information, I'd guess your NullPointerException occurs when you get an empty cursor. Try it this way:
//initialize arraylist, execute query etc.
if (cursor.moveToFirst()) {
do {
String[] entry = new String[dataSize];
//pull your data here
data[0] = cursor.getInt(0);
data[1] = cursor.getString(1);
//...
list.add(entry);
} while (cursor.moveToNext());
}
// return arraylist