在抽象访问时访问数据库中数据的最佳实践

时间:2012-05-03 03:00:26

标签: java android database design-patterns android-contentprovider

我正在尝试学习以下方案的最佳做法。

我有一组已定义的数据对象,这些对象随更新而变化。其中一些对象中包含其他对象的数组。

使用sqlite我使用以下模式设置数据库:每个对象都在桌面上。如果一个对象中有一个子对象,它对子表有一个fk

表名和对象可能会发生变化。因此,为了便于更改它们,我需要能够隐藏数据库调用。我还需要能够在插入数据库之前验证数据。此验证也因每个对象而异,并且每个对象可以有不同类型的验证。

目前我正在尝试为每个对象设置DAO。并为每个使用DatabaseHelper的对象提供ContentProviders以授予对数据库的访问权限。然后开发人员使用DAO来完成他们的工作。

它似乎变得非常丑陋和复杂。似乎还有一种更简单的方法......也许是ContentProviders的一些技巧。

那么,有没有将ContentProvider更好地整合到DAO模式中?或者有更好的方法来实现这一目标吗?

非常感谢任何建议。

2 个答案:

答案 0 :(得分:0)

我总是有数据库的单独包名。我编写了一个单独的Database类,我在每个项目中都使用它。我只更改数据库名称,表名称,列名称。以下是示例类:

package com.mobisys.android.contactwidget.database;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class ContactDatabase {
    public static final String DATABASE_NAME = "contact.db";
    public static final int DATABASE_VERSION = 1;
    public static final String CONTACT_TABLE_NAME = "contact";

    public static final String KEY_ID = "_id";
    public static final String KEY_ROW = "row";
    public static final String KEY_COL = "col";
    public static final String KEY_APP_WIDGET_ID = "app_widget_id";
    public static final String KEY_CONTACT_IMAGE = "image";
    public static final String KEY_CONTACT_NAME = "name";
    public static final String KEY_CONTACT_NUMBER = "number";
    public static final String KEY_CONTACT_EMAIL = "email";

    private final OpenHelper contactHelper;

    public ContactDatabase(Context context){
        contactHelper=new OpenHelper(context);
    }

    public long insert(String table, ContentValues values){
        return contactHelper.getWritableDatabase().insert(table, null, values);
    }

    public long delete(String table, String where, String[] whereArgs){
        return contactHelper.getWritableDatabase().delete(table, where, whereArgs);
    }   

    public int update(String table, ContentValues values, String whereClause, String[] whereArgs){
        return contactHelper.getWritableDatabase().update(table, values, whereClause, whereArgs);
    }

    public long countRows(String query){
        return DatabaseUtils.longForQuery(contactHelper.getReadableDatabase(), query, null);
    }

    public Cursor query(String table,String[] columns, String selection,String[] selectionArgs,String groupBy,String having,String orderBy){
        return contactHelper.getReadableDatabase().query(table, columns, selection, selectionArgs, groupBy, having, orderBy);
    }

    public void close(){
        contactHelper.close();
    }

    private static class OpenHelper extends SQLiteOpenHelper {

        OpenHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL("CREATE TABLE "+
                CONTACT_TABLE_NAME+
                " ("+ KEY_ID+" INTEGER PRIMARY KEY AUTOINCREMENT, "+
                KEY_ROW+" INT, "+
                KEY_COL+" INT, "+
                KEY_APP_WIDGET_ID+" INT, "+
                KEY_CONTACT_IMAGE+" BLOB, "+
                KEY_CONTACT_NAME+" TEXT, "+
                KEY_CONTACT_NUMBER+" TEXT, "+
                KEY_CONTACT_EMAIL+" TEXT"+")");
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int arg1, int arg2) {
            String alter_query1="alter table "+CONTACT_TABLE_NAME+" RENAME TO temp1;";
            db.execSQL(alter_query1);

            onCreate(db);

            String insert_query1="insert into "+CONTACT_TABLE_NAME+" select * from temp1;";
            db.execSQL(insert_query1);

            String delete_query1="DROP TABLE temp1;";
            db.execSQL(delete_query1);
        }

    }
}

我还创建了一个HelperDatabase类,它包含所有与数据库相关的静态方法。示例类:

package com.mobisys.android.contactwidget.database;

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

import com.mobisys.android.contactwidget.data.CONTACT;

public class HelperDatabase {

    public static long inserContact(CONTACT contact, ContactDatabase database){
        ContentValues values=new ContentValues();
        values.put(ContactDatabase.KEY_APP_WIDGET_ID, contact.app_widget_id);
        values.put(ContactDatabase.KEY_ROW, contact.row);
        values.put(ContactDatabase.KEY_COL, contact.col);
        values.put(ContactDatabase.KEY_CONTACT_NAME, contact.name);
        values.put(ContactDatabase.KEY_CONTACT_NUMBER, contact.cotact_number);
        values.put(ContactDatabase.KEY_CONTACT_EMAIL, contact.email);
        values.put(ContactDatabase.KEY_CONTACT_IMAGE, contact.image);

        long id=database.insert(ContactDatabase.CONTACT_TABLE_NAME, values);
        return id;
    }

    public static void updateMyContactInfo(ContactDatabase contactdb, int _id, String number){
        ContentValues values=new ContentValues();
        values.put(ContactDatabase.KEY_CONTACT_NUMBER, number);
        contactdb.update(ContactDatabase.CONTACT_TABLE_NAME, values, "_id"+"="+_id, null);
    }

    public static Cursor getContacts(ContactDatabase contactdb, int sort){
        if(sort==1)
            return contactdb.query(ContactDatabase.CONTACT_TABLE_NAME, null, null, null, null, null, ContactDatabase.KEY_CONTACT_NAME);
        else if(sort==2)
            return contactdb.query(ContactDatabase.CONTACT_TABLE_NAME, null, null, null, null, null, ContactDatabase.KEY_CONTACT_EMAIL);
        else if(sort==3)
            return contactdb.query(ContactDatabase.CONTACT_TABLE_NAME, null, null, null, null, null, ContactDatabase.KEY_CONTACT_NUMBER);

        return contactdb.query(ContactDatabase.CONTACT_TABLE_NAME, null, null, null, null, null, null);
    }

    public static boolean isContactExist(ContactDatabase contactdb, String number){
        return contactdb.countRows("SELECT COUNT(*) FROM "+ContactDatabase.CONTACT_TABLE_NAME+" WHERE"+ ContactDatabase.KEY_CONTACT_NUMBER + "='"+number+"'")>0;
    }   
}

所以,基本上,我可以为项目中的每个数据库和一个HelperDatabase类创建一个类,它可以完成所有插入,更新,检索和删除功能。

如果我的项目在很大程度上依赖于数据库,那么最好为您的数据库类创建一个静态对象,当您的主要活动将在主要活动将被破坏时开始和关闭时将打开该对象。

以下是代码示例:

public class HomeActivity extends Activity implements View.OnClickListener{
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        HelperDatabase.contactdb=new ContactDatabase(this);
        startApplication();
    }

    @Override
    public void onDestroy(){
        HelperDatabase.contactdb.close();
        super.onDestroy();
    }
}

希望,这对你有所帮助。

答案 1 :(得分:0)

我最近在.net中创建了一个数据访问层。我创建了一个BusinessObjectBase类以及一个BusinessObjectsBase(复数)类。将常用功能移到这些类中比最初想象的更具挑战性。以下是一些提示。

1)由于.Net是一种类型语言(也是Java),我需要获取有关基类虚函数所操作的派生类的类型信息。为了做到这一点,我使用了奇怪的重复模板模式(虽然我实际上没有听说过它,直到我自己意识到它的使用效果):http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern

基本上,它是一个泛型类,它将自己的类型作为泛型参数。

2)我很依赖反思。我不知道java在反射方式上提供了多少,或者它是否足够快以便对数据访问层有用。我不得不使用我在网上找到的免费的quickflect库,因为原生反射方法太慢了。

3)我使用PostSharp(Java让Spring做同样的事情)来处理变更跟踪,这样它只会在实际更改后更新对象。

4)好的,这是最重要的部分:保持简单。尽管我使用了一个奇怪的通用模式,反射和面向方面的编程来完全实现我想要的东西,但我的dll的核心实际上比你想象的更简单。我做了很多研究来找到完美的orm工具,但发现最后编写一些函数来动态生成我自己的sql语句并不困难。这是反射派上用场的地方,因为我将属性放在表示数据库中的表的类中,以及表示表中字段的属性上。这样,如果表或字段名称发生更改,您只需更改属性...

5)我创建了一个简短的app(几乎适合单个页面)来读取数据库表/字段,并动态生成包含每个表类的代码文件。

好吧,所以你可能不想创造复杂的东西,但我想我会根据自己的经验提出一些想法,也许你会发现其中一个或多个有用:)

(作为旁注,我知道很多人会想:为什么你经历了所有麻烦而不是仅使用现有的ORM。我发现现有的ORM使用过于繁琐,我的实施是比我研究过的任何ORM更轻巧,更快速。