繁体   English   中英

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

[英]How can I efficiently refactor SQLite access in Java?

我正在用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,但是我的问题是,如果没有一个ORM,有人将如何解决这个问题。)

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

在SQLite中,准备好的语句真的可以提高性能吗?

首先,您不想在Java代码中执行以下几行:

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

可以按照您的建议进行操作,在Java之类的语言中,这称为反射。 https://zh.wikipedia.org/wiki/Reflection_(计算机编程)

在这种情况下(很多情况下),使用反射进行所需的操作是一个坏主意,原因有很多。

列举一些:

您的代码应采用不同的结构以避免这种方法。

可悲的是,我确实相信,因为它是严格键入的,所以您无法自动执行代码的这一部分:

// 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/的操作 即将数据库哈希值转换为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;
    }
}

因此,我还没有完全研究的另一种选择是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上电话。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM