一些额外的/替代的方法。
我个人的方法是上述两种方法的替代方法,虽然是在应用程序中创建表的扩展,但它一直是创建类,a) 简化表创建,b) 满足有限的动态添加表和列.
它的优点是列、表和索引只有一个命名点(我认为这是在应用程序之外定义数据库的缺陷)。
它的优点是可以直接重复使用。尽管它的缺点是创建底层类需要花费时间(这对我来说是一个好处,因为我学到了很多对 Java 和 Android 都是新的东西)。
它不需要处理从资产文件夹复制/管理数据库的复杂性(你说没有,我的观察是 SO 上更频繁发生的 Android SQlite 问题之一是关于从资产文件夹复制数据库时出现问题)。
可能会被问到的一些问题,App 是如何处理删除 App 数据的?如果您保留数据库的副本以适应这种情况,则会占用额外的空间(我相信仅一个数据库加上每个表的 4k 可能约为 36k(这只是来自对单个数据库/表的观察,所以不是在任何深度进行调查))。我怀疑额外代码的空间是否会如此之多,但也许可以进行调查。
它还不能满足外键/约束或触发器
(从未使用过)。
有5个类DBColumn、DBTable、DBIndex、DBDatabase和SQLKWORDS。
SQLKWORDS 包含常用 SQL KEYWORDS 的定义,例如
public class SQLKWORD {
public static final String SQLTABLE = " TABLE ";
public static final String SQLCREATE = " CREATE ";
public static final String SQLDROP = " DROP ";
public static final String SQLINDEX = " INDEX ";
public static final String SQLUNIQUE = " UNIQUE ";
.....
}
DBColumn 用于定义列
这些用于逐步构建 DBDatabase,这基本上是所需的模式以及各种方法,例如actionBuildSQL 将添加任何不存在的表,免费的actionAlterSQL 用于添加新列。
例如定义一个表(4列前3构成主索引(第3个参数如果是PRIMARY INDEX的一部分,则为true,否则为false)):-
import mjt.dbcolumn.DBColumn;
import mjt.dbtable.DBTable;
import static mjt.sqlwords.SQLKWORD.*;
public class DBCardPayeeLinkTableConstants {
static final String CARDPAYEELINK_TABLE = "cardpayeelink";
private static final String CARDREF_COL = "cardref";
private static final String PAYEEREFCOL_COL = "payeeref";
private static final String USERREF_COL = "userref";
private static final String USAGE_COUNT_COL = "usagecount";
// DBCOlumns
static final DBColumn CARDREF = new DBColumn(
CARDREF_COL,
SQLINTEGER,
true,
""
);
static final DBColumn PAYEEREF = new DBColumn(
PAYEEREFCOL_COL,
SQLINTEGER,
true,
""
);
static final DBColumn USERREF = new DBColumn(
USERREF_COL,
SQLINTEGER,
true,
""
);
static final DBColumn USAGECOUNT = new DBColumn(
USAGE_COUNT_COL,
SQLINTEGER,
false,
"0"
);
static final ArrayList<DBColumn> CARDPAYEELINKCOLUMNS =
new ArrayList<>(
Arrays.asList(
CARDREF,
PAYEEREF,
USERREF,
USAGECOUNT
)
);
static final DBTable CARDPAYEELINKS = new DBTable(
CARDPAYEELINK_TABLE,
CARDPAYEELINKCOLUMNS
);
// define full column names i.e. table.columnname
public static final String CARDREF_FCOL =
CARDREF.getFullyQualifiedDBColumnName();
public static final String PAYEEREF_FCOL =
PAYEEREF.getFullyQualifiedDBColumnName();
public static final String USEREF_FCOL =
USERREF.getFullyQualifiedDBColumnName();
public static final String USAGECOUNT_FCOL =
USAGECOUNT.getFullyQualifiedDBColumnName();
}
有许多 DBCOlumn 构造函数,例如DBColumn(true) 将创建常用的 _id 列。从上面可以看出,方法也是多种多样的。
DBTable 获取一个 DBColumns 列表,而 DBDatabase 获取一个 DBTables 列表(如果需要,DBIndexes 本身就是一个 DBTable 和一个 DBColumns 列表)。 DBDatabase 的方法如actionAlterSQL 将所需的模式与实际的当前模式进行比较。
然后我会有一个如下的课程:-
class DBConstants {
/*
Define the database name
*/
static final String DATABASENAME = "cardoniser";
static final int DATABASEVERSION = 1;
/*
Define the DBDatabase instance (base schema),
it consists of the DBTable instances which are
comproised of DBColumns (and optionally DBindex instances)
*/
static final DBDatabase cardonsier = new DBDatabase(DATABASENAME,
new ArrayList<>(Arrays.asList(
DBCardsTableConstants.CARDS,
DBUsertableConstants.USERS,
DBPreftableConstants.PREFS,
DBPayeestableContants.PAYEES,
DBCategoriestableConstants.CATEGORIES,
DBCardCategoryLinkTableConstants.CARDCATEGORYLINKS,
DBCardPayeeLinkTableConstants.CARDPAYEELINKS,
DBTransactionsTableConstants.TRANSACTIONS
))
);
}
在我的 DBHelper 中我有(onUpgrade、onCreate 中没有做任何事情,只是调用 onExpand):-
@Override
public void onCreate(SQLiteDatabase db) {
usable = this.onExpand(db,false);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldversion, int newversion) {
}
public boolean onExpand(SQLiteDatabase db, boolean buildandexpand) {
boolean rv = true;
if (db == null) {
db = instance.getWritableDatabase();
}
// Is the Database definition valid to use?
if (DBConstants.cardonsier.isDBDatabaseUsable()) {
ArrayList<String> buildsql = DBConstants.cardonsier.generateDBBuildSQL(db);
// Anything to build
// will not be if database is unchanged rather than
// if no definitions/valid definitions as this would
// be detected by isDBDatabaseUsable
if (!buildsql.isEmpty()) {
// YES so build the Database
DBConstants.cardonsier.actionDBBuildSQL(db);
}
if (buildandexpand) {
ArrayList<String> altersql = DBConstants.cardonsier.generateDBAlterSQL(db);
if (!altersql.isEmpty()) {
DBConstants.cardonsier.generateExportSchemaSQL();
}
}
}
else {
rv = false;
}
return rv;
}
public boolean isDBUsable() {
return usable;
}
在我最初的活动中,它将应用任何表或行添加以及索引添加、删除或更改(删除并重新创建索引):-
DBDAO dbdao = new DBDAO(this);
DBHelper.getHelper(this).onExpand(dbdao.getDB(),true);
除此之外,我对每个表使用一个类(实际上是两个,因为我还有一个单独的类用于特定于表的方法)。
总而言之,几乎没有复杂性问题,对我来说,在完成基础工作后,这三个选项都更好。
另一个可以考虑的选项。
有很多 SQLite 数据库工具,例如SQLite Manager(浏览器扩展),允许您创建数据库并导出 SQL。
例如上述数据库(非常接近它)是从 SQL 管理器中检索到的:-
CREATE TABLE android_metadata (locale TEXT);
CREATE TABLE cardcategorylink (cardref INTEGER , categoryref INTEGER , usagecount INTEGER DEFAULT 0 , PRIMARY KEY (cardref, categoryref) );
CREATE TABLE cardpayeelink (cardref INTEGER , payeeref INTEGER , usagecount INTEGER DEFAULT 0 , PRIMARY KEY (cardref, payeeref) );
CREATE TABLE cards (_id INTEGER PRIMARY KEY, cardname TEXT , cardtyperef INTEGER DEFAULT 0 , cardnumber TEXT );
CREATE TABLE categories (_id INTEGER PRIMARY KEY, categoryname TEXT );
CREATE TABLE payees (_id INTEGER PRIMARY KEY, payeename TEXT );
CREATE TABLE prefs (_id INTEGER PRIMARY KEY, prefname TEXT , preftype TEXT , prefvalue TEXT , prefshortdesc TEXT , preflongdesc TEXT );
CREATE TABLE transactions (_id INTEGER PRIMARY KEY, timestamp INTEGER DEFAULT 0 , cardref INTEGER DEFAULT 0 , payeeref INTEGER DEFAULT 0 , categoryref INTEGER DEFAULT 0 , amount REAL DEFAULT 0.00 , flags INTEGER DEFAULT 0 );
CREATE TABLE users (_id INTEGER PRIMARY KEY, username TEXT , userhash TEXT , usersalt TEXT );
(请注意,上面的数据库实际上是通过Android设备管理器复制到SQLite管理器中的,所以它确实是使用我采用的方法生成的)。
如果您的来源是 MySQL 或其他来源,那么我相信 PHPMyAdmin 具有类似的功能。