在抽象访问时访问数据库中数据的最佳实践
Posted
技术标签:
【中文标题】在抽象访问时访问数据库中数据的最佳实践【英文标题】: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
模式中?或者有没有更好的方法来实现这个目标?
非常感谢任何建议。
【问题讨论】:
无论你做什么,这都会让人头疼:) 【参考方案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 中提到的目标的唯一方法。以上是关于在抽象访问时访问数据库中数据的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章