【问题标题】:best practice for accessing data in a database while abstracting the accessing在抽象访问时访问数据库中数据的最佳实践
【发布时间】:2012-05-12 13:32:01
【问题描述】:

我正在尝试学习以下场景的最佳实践。

我有一组已定义的数据对象,它们会随着更新而改变。其中一些对象中包含其他对象的数组。

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

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

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

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

那么,有没有办法更好地将ContentProvider 集成到DAO 模式中?或者有没有更好的方法来实现这个目标?

非常感谢任何建议。

【问题讨论】:

  • 无论你做什么,这都会让人头疼:)

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


【解决方案1】:

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

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

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

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

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

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

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

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

(作为旁注,我知道很多人会想:为什么你要经历所有这些麻烦而不是仅仅使用现有的 ORM。我发现现有的 ORM 使用起来过于麻烦,而我的实现是比我研究过的任何 ORM 都更轻量和更快)

【讨论】:

    【解决方案2】:

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

    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();
        }
    }
    

    希望对你有所帮助。

    【讨论】:

    • 这不是使用ContentProvider。我正在寻找一种将 ContentProvider 集成到 DAO 模式中的方法。这似乎是实现这一目标的一种方式,但我真的很想使用ContentProvider 来实际进行我的数据库调用,并且仍然有一个类似于DAO 模式的抽象层。看来这将是真正实现我在 OP 中提到的目标的唯一方法。
    猜你喜欢
    • 2015-09-10
    • 1970-01-01
    • 2011-02-21
    • 2022-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多