Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

For my simple Android application I don't want to use an ORM, anyway I'd like to have a db-communcation layer easy to user, to read and efficient. This is my solution: every entity (ex: Person) as an helper that do the CRUD functions (ex: PersonHelper). The helper extends another class (EntityHelper), that contains the logic not related to the specific entity.

This is the code for the EntityHelper:

package com.dw.android.db;

import java.util.ArrayList;
import java.util.List;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;

import com.dw.android.db.model.Entity;

/**
 * Helper base class used to do CRUD operations
 * 
 * @param <T> Managed entity class
 * @author atancredi
 */
public abstract class EntityHelper<T extends Entity> {
    protected final SQLiteOpenHelper dbHelper;

    public EntityHelper(SQLiteOpenHelper dbHelper) {
        this.dbHelper = dbHelper;
    }

    /**
     * Load a record from database
     * 
     * @param id Entity id
     * @return The entity list loaded from entity table
     */
    public T get(long id) {
        T retv = null;
        //
        SQLiteDatabase db = dbHelper.getReadableDatabase();     
        Cursor cursor = null;
        try {
            SQLiteQueryBuilder qb= new SQLiteQueryBuilder();
            qb.setTables(getTable());
            cursor = qb.query(db, getColumns(), "_id = ?", new String[]{ String.valueOf(id) }, null, null, null);
            if(cursor.moveToFirst()) {
                retv = bind(cursor);
            }
        } finally {
            if(cursor != null) {
                cursor.close();
            }
            db.close();
        }
        //
        return retv;
    }

    /**
     * Load all record from database
     * @return The entity list loaded from entity table
     */
    public List<T> all() {
        List<T> retv = new ArrayList<T>();
        //
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        SQLiteQueryBuilder qb= new SQLiteQueryBuilder();
        qb.setTables(getTable());
        Cursor cursor = null;
        try {
            cursor = qb.query(db, getColumns(), null, null, null, null, null);
            if(cursor.moveToFirst()) {
                do {
                    retv.add(bind(cursor));
                } while(cursor.moveToNext());
            }
        } finally {
            if(cursor != null) {
                cursor.close();
            }
            db.close();
        }
        //
        return retv;
    }

    /**
     * Update an entity on DB using his id as selection
     * 
     * @param entity Entity to update
     * @return true, if a row has been update
     */
    public boolean update(T entity) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        boolean updated = true;
        try {
            db.beginTransaction();
            int count = db.update(getTable(), bind(entity), "_id = ?", new String[]{ String.valueOf(entity.getId()) });
            updated = count > 0;
            db.setTransactionSuccessful();
        } finally {
            db.endTransaction();
            db.close();
        }
        return updated;
    }

    /**
     * Insert an entity on the DB
     * 
     * @param entity Entity to insert
     * @return The DB generated id for the entity
     */
    public long insert(T entity) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        long retv = -1;
        try {
            db.beginTransaction();
            retv = db.insert(getTable(), null, bind(entity));
            db.setTransactionSuccessful();
            if(retv >= 0) {
                entity.setId(retv);
            }
        } finally {
            db.endTransaction();
            db.close();
        }
        return retv;
    }

    /**
     * Delete an entity
     * @param id Entity id
     * @return true, if the entity was in the DB
     */

    public boolean delete(T entity) {
        return delete(entity.getId());
    }

    /**
     * Delete an entity
     * @param id Entity id
     * @return true, if the entity was in the DB
     */
    public boolean delete(long id) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        boolean deleted = false;
        try {
            db.beginTransaction();
            int count = db.delete(getTable(), "_id = ?", new String[]{ String.valueOf(id) });
            deleted = count > 0;
            db.setTransactionSuccessful();
        } finally {
            db.endTransaction();
            db.close();
        }
        return deleted;
    }

    /**
     * Build the columns array using an enum
     * 
     * @return The columns array, that can be used for a projection
     */
    protected String[] getColumns() {
        Enum<?>[] columns = getColumnsEnum();
        String[] retv  = new String[columns.length];
        for(int i = 0, len = columns.length; i < len; i++) {
            retv[i] = columns[i].name();
        }
        return retv;
    }

    /**
     * Bind a record to an entity for insert.
     * Remember to not bind the entity id!
     * 
     * @param cursor Cursor from DB
     * @return The binded entity
     */
    protected abstract T bind(Cursor cursor);

    /**
     * Bind an entity to a ContentValues
     * 
     * @param entity The entity
     * @return A ContentValues object that contains the record values
     */
    protected abstract ContentValues bind(T entity);

    /**
     * Get the table name for the enttiy
     * 
     * @return The table name
     */
    public abstract String getTable();

    /**
     * Get the enum that define all columns for the entity table
     * 
     * @return The enum values
     */
    public abstract Enum<?>[] getColumnsEnum();

}

This is an example of class that extends EntityHelper:

package com.dw.svegliatest.db.model;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteOpenHelper;

import com.dw.android.db.EntityHelper;
import com.dw.utils.time.Days;

/**
 * Alarm entity helper
 * 
 * @author atancredi
 */
public final class AlarmHelper extends EntityHelper<Alarm> {
    public AlarmHelper(SQLiteOpenHelper dbHelper) {
        super(dbHelper);
    }

    /**
     * {@inheritDoc}
     */
    protected ContentValues bind(Alarm entity) {
        ContentValues record = new ContentValues();
        //
        record.put(Columns.label.name(), entity.getLabel());
        record.put(Columns.enabled.name(), entity.isEnabled());
        record.put(Columns.time.name(), entity.getTime());
        record.put(Columns.days.name(), entity.getDays().flags());
        //
        return record;
    }

    /**
     * {@inheritDoc}
     */
    protected Alarm bind(Cursor cursor) {
        Alarm alarm = new Alarm();
        //
        alarm.setId(cursor.getLong(Columns._id.ordinal()));
        alarm.setLabel(cursor.getString(Columns.label.ordinal()));
        alarm.setEnabled(cursor.getInt(Columns.enabled.ordinal()) == 1);
        alarm.setTime(cursor.getLong(Columns.time.ordinal()));
        alarm.setDays(new Days(cursor.getInt(Columns.days.ordinal())));
        //
        return alarm;
    }

    /**
     * {@inheritDoc}
     */
    public String getTable() {
        return "Alarm";
    }

    /**
     * {@inheritDoc}
     */
    public Enum<?>[] getColumnsEnum() {
        return Columns.values();
    }

    /**
     * Alarm columns definition
     * 
     * @author atancredi
     */
    public static enum Columns {
        _id,
        label,
        enabled,
        time,
        days
    }
}

What do you think about the code and the idea of use an enum for table columns? Thanks.

share|improve this question

Know someone who can answer? Share a link to this question via email, Google+, Twitter, or Facebook.

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.