Tuesday 22 January 2013

Db4o Concurrent Access

Db4o has access limitations, which means you cannot use the ObjectContainer to query/store objects in different process than the one it was opened in. For example if you open db

ObjectContainer db= Db4oEmbedded.openFile(Db4oEmbedded.newConfiguration(),
DB_PATH);

You cannot use this ObjectContainer, db for database operations in other processes. If you try to open db again in some other process you might get
DatabaseFileLockedException. So db4o don't allow concurrent access this way. However, in real world applications, we need to perform database operations in many different threads, AsyncTask and services. To perform such concurrent operations in isolation, db4o provides many mechanisms, one of which is, opening different db sessions in different processes. Once you have opened the database, You can use it to open session in different process like:

ObjectContainer db_session= db.ext.openSession();

now we can execute all db operations with this ObjectContainer e.g

  db_session.store(someObj);
  db_session.commit();

However, keep in mind, that you need to explicitly close the session by

  db_session.Close();
 
Below is a helper class, can be used to open/close db.

//////////////////////////////////////////////////////////////////////////////////////
public class dbHelper {

private static ObjectContainer database;
private static final String DATABASE_NAME = "My_database.db4o";
private static final int DATABASE_MODE = 0;
 private static Context ctx;

public dbHelper(Context context) {

   ctx=context;
   database=null;

}

private OpenDatabse(){

try {
if (database == null) {
database = Db4oEmbedded.openFile(Db4oEmbedded.newConfiguration(),
db4oDBFullPath());
}
} catch (Exception ie) {
Log.e(DbHelper.class.getName(), ie.toString());
}


}

private String db4oDBFullPath() {
return ctx.getDir("data", DATABASE_MODE) + "/" + DATABASE_NAME;
}

public void close() {
if (this.database != null) {
this.database.close();
}
}

public ObjectContainer getDatabaseSession() {

         return database.ext().openSession();
}

}


/////////////////////////////////////////////////////////////////////////////////

Using this helper class we can pen the db somewhere at application start,


dbHelper helper= new dbHelper(context);
helper.OpenDatabse();

and close the db some where at application finish, by

helper.CloseDb();

Now in any process where you want to access db, use getSession method

ObjectContainer db= helper.getDatabaseSession();

db.store(someObj);
db.commit();
db.Close();

 That's it about concurrent access, hope it will be helpful.

Tuesday 8 January 2013

Using Database for Object (db4o) in android part-2

In previous post we discussed db4o benefits over relational databases and saw how we can setup and use db4o in android applications.

Today we will go little deeper in understanding the advance functionality of  db4o and its querying mechanism. QBE is easy but We need more sophisticated  mechanisms of querying in actual android applications, and that's Native Queries.

Native queries provide us absolute power of conditional querying. We can query an object by any of its fields and using all conditional operators and we can combine our quries using logical operators AND, OR, NOT. Lets start with an example. Lets say we have a  Contact class

Class Contact{
    Public String name;
    Public String number;
    Public int age;
    Public boolean member;
}

Querying based on conditions is very easy in db4o than in relational databases. We have a predicate function   in which we can write any condition which should be true. Lets see :

Find a contact where number= 1234


ObjectSet<Contact> result = db.query(new Predicate<Contact>() {
public boolean match(Contact conObj) {
return (conObj.number.equal("1234"));
}
});

find a contact where age=20


ObjectSet<Contact> result = db.query(new Predicate<Contact>() {
public boolean match(Contact conObj) {
return (conObj.age==20);
}
});

to get all objects of type Contact

ObjectSet<Contact> result = db.query(new Predicate<Contact>() {
public boolean match(Contact conObj) {
return true;
}
});



Note that we are using db.query instead of db.QBE. db.query return us one or more matching objects in result which Contact type object set. We can iterate result to get objetcs. We can write any expression in match function which should be true when querying objects.

To retrieve found objects, check the result returned by db.query

if(result.hasNext()) // if result is not empty
   Contact obj= result.Next();


and if you want to return all objects returned by query

ArrayList<Contact> list=new ArrayList<Contact>();

while(result.hasNext()){
  list.add(result.Next());
}


that's it about native queries. There are some other interesting things like indexing for  fast querying and dealing with objects containing other objects. You are encouraged to read about them in db4o reference document and tutorial.