Thursday 13 September 2012

Using database for objects (db4o) in android part-1

Mapping object paradigm to relational paradigm is very hectic job for programmer and intensive for processor. As mobile development move to object oriented paradigm, we need object based database where we can directly store/retrieve/update and delete objects without first converting them to relational table entities.

Fortunately we have db4o, which was released just after first release of android. db4o is database for objects. when we say "objects" this means objects are not converted to relational tables at any stage (neither by programmer nor by framework). db4o is fast, has small footprint and low processing overhead. You can read about performance comparison with other mobile databases  here.

In this post I'll explain:
  1. How to setup db4o to use in android project using eclipse. and
  2. How to perform CRUD operations on simple objects.

In order to setup db4o for your project, download latest version db4o library, extract the zip and put db4o-all.jar in your lib folder and update java build path.


Lets say we have custom class, Contact.java:

public class Contact {

    private String name;

    private String number;

    int age;

    boolean member;

    public Contact() {

        // default constructor

        name = null;

        number = null;

        age = 0;

        member = false;

    }

    public Contact(String name, String number, int age, boolean member) {

        this.name = name;

        this.number = number;

        this.age = age;

        this.member = member;

    }

    public String getNumber() {

        return number;

    }

    public void setNumber(String number) {

        this.number = number;

    }

    public int getAge() {

        return age;

    }

    public void setAge(int age) {

        this.age = age;

    }

    public boolean isMember() {

        return member;

    }

    public void setMember(boolean member) {

        this.member = member;

    }


    public void setName(String name) {

        this.name = name;

    }


    public String getName() {

        return name;

    }


    public String toString() {


        return name + "/" + number + "/" + Integer.toString(age) + "/"

                + Boolean.toString(member);

    }


}



Now lets start working with db40, first open the database:

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



ObjectContainer is the db4o type which hold the database reference. We will use this reference to call all db4o methods for CRUD. There various options we can set using configuration, for the time being lets just use the default configuration Db4oEmbedded.newConfiguration().

Once database is open, we can store, retrieve update and delete objects:
  • Inserting objects:
    • store(Object o) method of ObjectContainer is used to insert new objects in database. e.g
           
 Contact con= new Contact("sohail", "111", 10, true);
 db.store(con);
 db.commit();
         

  • Querying objects:
    • There are two methods we can use to retrieve stored objects, these are: 
      • queryByExample(Object o) and
      • native query
In this tutorial, I'll use queryByExample which is simple and understand  for  beginners.

queryByExample takes and object and retrieve object/s similar to object supplied in arguments. In order to get all objects, we need to pass a dummy object whose all fields are set to null/0.

For example to get all objects where age=10,

 

Contact c=new Contact(null,null,10,true);

ObjectSet list=db.queryByExample(c);

this will return a list of all objects where age=10.

To fetch all objects of type Contact:

Contact t= new Contact();

ObjectSet list= db.queryByExample(t);



this will return all the objects of type Contact, Note that default constructor initializing all the fields to null and zeros. This is necessary to fetch all object. ObjectSet is db4o type which can be think of list of objects.


  • Updating objects:
    • In order to update an object, we need to first query that object and then we can update it using store method. e.g to update object where name= sohail
 

Object q=new Object();

q.setName("sohail);

ObjectSet result= db.queryByExample(q);



if(result.hasNext())

{

    Contact c= (Contact) result.next();

    //update age,number

    c.setAge(33);

   c.setNumber("444444444"); 

  db.store(c);



}

 

what we are doing here is to find the object where name=sohail, if found (result.hasNext) then update it.

  • Deleting Objects:
    • like updating, in order to delete objects we need to first query that object and bring it into memory, then we can use delete() method to delete.e.g deleting object where contact name=sohail
 

Contact n=new Contact();

n.setName("sohail");

ObjectSet result= db.queryByExample(n);



if(result.hasNext())

{

     Contact d=(Contact) result.next(); 

     db.delete(d);

}


Thats all. QueryByExample is simple however it has some limitations, we will discuss native queries in next tutorial which use the semantic of programming language, give more control and are recommended.


Full source:
package sohail.aziz.db4oexample;
import java.util.ArrayList;
import android.util.Log;
import com.db4o.Db4oEmbedded;
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;

public class DbHelperQBE {

    String dbpath;
    ObjectContainer db;

    boolean OpenDb(String name) {

        if (name != null) {

            db = Db4oEmbedded.openFile(Db4oEmbedded.newConfiguration(), name);

            return true;

        }

        return false;

    }


    void CloseDb() {

        db.close();

    }

    void emptyDb(){
   
        ObjectSet result= db.queryByExample(new Object());
    
        while(result.hasNext()){

               db.delete(result.next());   

        }
     

    }


    void StoreContact(Contact con) {

        db.store(con);

        db.commit();

        Log.d("sohail", "object stored");

    }

    Contact getContactByName(String name) {

       // define

        Contact obj = new Contact();

        obj.setName(name);

        ObjectSet result = db.queryByExample(obj);


        if (result.hasNext()) {

            return (Contact) result.next();

        }

        return null;

    }

    Contact getContact(Contact con) {

        ObjectSet result = db.queryByExample(con);


        if (result.hasNext()) {

            return (Contact) result.next();

        } else

            return null;

    }


    ArrayList<Contact> getAllContacts() {


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

        Contact proto = new Contact();

        ObjectSet<Contact> result = db.queryByExample(proto);


        while (result.hasNext()) {

            list.add(result.next());

        }

        return list;

    }

    boolean updateObject(Contact ObjTo, Contact ObjFrom) {



        Contact found = null;

        ObjectSet<Contact> result = db.queryByExample(ObjTo);

        if (result.hasNext()) { // if found

            found = result.next();

            found.setAge(ObjFrom.getAge()); // shallow copy just replay to, to From.

            found.setMember(ObjFrom.isMember());

            found.setName(ObjFrom.getName());

            found.setNumber(ObjFrom.getNumber());

            db.store(found);

            db.commit();

            return true;

        }

        return false;

    }

    boolean deleteObject(Contact p) {

        Contact found = null;
        ObjectSet<Contact> result = db.queryByExample(p);

        if (result.hasNext()) {

            found = result.next();
            db.delete(found);

            return true;

        } else {

            return false;

        }

    }

}