如何在Java中有效地重构SQLite访问?

时间:2014-01-22 23:10:41

标签: java android sqlite refactoring

我正在用Java编写一个Android应用程序,它使用包含许多表的SQLite数据库。我设置了一些数据源类来从这些表中提取数据并将它们转换为各自的对象。我的问题是我不知道构建用Java访问数据库的代码的最有效方法。

数据源类变得非常重复并且需要很长时间才能编写。我想将重复重构为一个父类,它将抽象出大部分访问数据库和创建对象的工作。

问题是,我是一名PHP(松散类型)程序员,而且我很难以严格打字的方式解决这个问题。

用PHP思考,我做了类似的事情:

public abstract class Datasource {

    protected String table_name;
    protected String entity_class_name;

    public function get_all () {

        // pseudo code -- assume db is a connection to our database, please.
        Cursor cursor  =  db.query( "select * from {this.table_name}");

        class_name  =  this.entity_class_name;
        entity  =  new $class_name;

        // loops through data in columns and populates the corresponding fields on each entity -- also dynamic
        entity  =  this.populate_entity_with_db_hash( entity, cursor );

        return entity;
    }
}

public class ColonyDatasource extends Datasource {

    public function ColonyDataSource( ) {
        this.table_name  =  'colony';
        this.entity_class_name  =  'Colony';
    }
}

然后new ColonyDatasource.get_all()将得到表colony中的所有行并返回一堆Colony对象,并为每个表创建数据源就像创建一个只有一个表映射的类一样简单课堂信息的信息。

当然,这种方法的问题是我必须声明我的返回类型,并且不能在Java中使用变量类名。所以现在我被卡住了。

应该做什么呢?

(我知道我可以使用第三方ORM,但我的问题是如果没有人可以解决这个问题。)

3 个答案:

答案 0 :(得分:0)

如果您的查询除了某些参数外几乎相同,请考虑使用预准备语句和绑定

In SQLite, do prepared statements really improve performance?

答案 1 :(得分:0)

首先,您不希望在Java代码中执行这些行:

class_name  =  this.entity_class_name;
entity  =  new $class_name;

可以按照您的建议进行操作,而在Java等语言中则称为反射。 https://en.wikipedia.org/wiki/Reflection_(computer_programming)

在这个(很多情况下)使用反射做你想做的事情是个坏主意,原因很多。

列举一些:

您的代码应以不同的方式构建,以避免此类方法。

可悲的是,我确实相信,因为它是严格打字的,你不能自动化这部分代码:

// loops through data in columns and populates the corresponding fields on each entity -- also dynamic
        entity  =  this.populate_entity_with_db_hash( entity, cursor );

除非你通过反思来做到这一点。或完全转换方法并开始序列化您的对象(不推荐,只是说它是一个选项!)。或者做类似于Gson https://code.google.com/p/google-gson/的事情。即将db哈希转换为json表示,然后使用gson将其转换为对象。

你可以做的是,自动化抽象类中对象的“get_all”部分,因为几乎每个实例都会重复,但是使用一个实现,这样你就可以让抽象函数放心,它可以调用一个它的扩展对象的方法。这将使您大多数采用“自动”方法,减少必须重新键入的代码量。

要做到这一点,我们必须考虑Java有这样一个事实:

尝试这样的事情(高度未经测试,很可能不会编译)代码:

// Notice default scoping
interface DataSourceInterface {
    //This is to allow our GenericDataSource to call a method that isn't defined yet.
    Object cursorToMe(Cursor cursor);
}

//Notice how we implement here?, but no implemented function declarations!
public abstract class GenericDataSource implements DataSourceInterface {
    protected SQLiteDatabase database;

    // and here we see Generics and Objects being friends to do what we want.
    // This basically says ? (wildcard) will have a list of random things
    // But we do know that these random things will extend from an Object
    protected List<? extends Object> getAll(String table, String[] columns){
        List<Object> items = new ArrayList<Object>();

        Cursor cursor = database.query(table, columns, null, null, null, null,null);
        cursor.moveToFirst();
        while (!cursor.isAfterLast()) {
            // And see how we can call "cursorToMe" without error!
            // depending on the extending class, cursorToMe will return 
            //   all sorts of different objects, but it will be an Object nonetheless!
            Object object = this.cursorToMe(cursor);
            items.add(object);
            cursor.moveToNext();
        }
        // Make sure to close the cursor
        cursor.close();
        return items;
    }
}

//Here we extend the abstract, which also has the implements.
// Therefore we must implement the function "cursorToMe"
public class ColonyDataSource extends GenericDataSource {
    protected String[] allColumns = {
        ColonyOpenHelper.COLONY_COLUMN_ID, 
        ColonyOpenHelper.COLONY_COLUMN_TITLE, 
        ColonyOpenHelper.COLONY_COLUMN_URL
    };

    // Notice our function overloading!
    //    This getAll is also changing the access modifier to allow more access
    public List<Colony> getAll(){
        //See how we are casting to the proper list type?
        // Since we know that our getAll from super will return a list of Colonies.
        return  (List<Colony>)super.getAll(ColonyOpenHelper.COLONY_TABLE_NAME, allColumns);
    }


    //Notice, here we actually implement our db hash to object
    // This is the part that would only be able to be done through reflection or what/not
    // So it is better to just have your DataSource object do what it knows how to do.
    public Colony cursorToMe(Cursor cursor) {
        Colony colony = new Colony();
        colony.setId(cursor.getLong(0));
        colony.setTitle(cursor.getString(1));
        colony.setUrl(cursor.getString(2));
        return colony;
    }
}

答案 2 :(得分:0)

所以我还没有完全探索的另一个选择是Java Persistence API,有些项目实现了与此非常相似的注释。其中大部分是ORM形式,为您提供数据访问对象(http://en.wikipedia.org/wiki/Data_access_object

一个名为“Hibernate”的开源项目似乎是Java中ORM的首选解决方案之一,但我也听说过这是一个非常重的解决方案。特别是当你开始考虑移动应用时。

一个特定于Android的ORM解决方案被称为OrmLite(http://ormlite.com/sqlite_java_android_orm.shtml),它基于Hibernate,但是为了将它放在Android手机上的目的非常简单,没有多少依赖。< / p>

我已经读过,使用其中一个的人会很好地过渡到另一个人。