【问题标题】:Can Android Room manage multiple databases and create databases from a template database?Android Room 可以管理多个数据库并从模板数据库创建数据库吗?
【发布时间】:2021-11-10 19:29:15
【问题描述】:

关于以下最佳实践或选项的任何想法、建议或想法?

问题:使用 Android Room,在单个 Android 应用程序中创建和处理多个数据库的实用方法是什么?

我正在尝试做的事情:我有一个 Android 应用程序,旨在管理多个研究主题。这个想法是用户可以创建特定于主题或研究的数据库,并能够存储这些主题的来源、附件和注释。例如,用户可以拥有一个特定于现代音乐历史的数据库,一个关于狩猎历史主题的第二个数据库,甚至可以拥有像微生物研究这样深入的主题。

我的想法是拥有单独的数据库而不是一个存储所有这些数据的数据库。特别是因为附件可以存储并很快占用空间。这些数据库可以在手机/平板应用程序和桌面版本之间共享。有一个 Java 桌面版本正在使用。

我做了什么我真的只在这里搜索过并用谷歌搜索了一些但似乎有点模糊。我熟悉并将更改迁移到数据库但不确定如果这始终是创建新数据库以及重命名等的最佳方式。

此 Android 应用附带一个预定义和预填充的数据库作为演示。这个数据库已经 2 年没有改变了。所以,这个想法可能是有一个“template.db”,可以用来创建新的数据库并相应地重命名它们。

【问题讨论】:

    标签: android sqlite android-room


    【解决方案1】:

    对于 Android Room,在单个 Android 应用中创建和处理多个数据库的实用方法是什么?

    您当然可以处理多个数据库和基于相同架构的多个数据库。

    问题是如何确定可以使用哪些数据库。如果所有数据库都位于同一路径(或什至多个路径)中,则可以使用此方法。另一种方法可能是拥有数据库的数据库。

    这是一个利用数据库的数据库(“MasterDatabase”)并允许访问 x 个数据库的示例。

    首先是 MasterDatabase,它有一个简单的表,其中有一个 id 列(可以省略)和一个用于数据库名称的列。表 (@Entity) 被命名为 MasterDatabaseList 根据:-

    @Entity(
            indices = { @Index(value = "databaseName", unique = true)
            }
    )
    class MasterDatabaseList {
        @PrimaryKey
        Long id;
        String databaseName;
    
        public MasterDatabaseList() {}
    
        @Ignore
        public MasterDatabaseList(String databaseName) {
            this.databaseName = databaseName;
        }
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getDatabaseName() {
            return databaseName;
        }
    
        public void setDatabaseName(String databaseName) {
            this.databaseName = databaseName;
        }
    }
    
    • 注意 databaseName 列上的唯一索引

    伴随着桌子的是MasterDao一个@Dao类:-

    @Dao
    abstract class MasterDao {
        @Insert(onConflict = OnConflictStrategy.IGNORE)
        abstract long insert(MasterDatabaseList masterDatabaseList);
        @Query("SELECT * FROM masterdatabaselist")
        abstract List<MasterDatabaseList> getAllDatabases();
    }
    
    • 允许插入或提取行。
    • 将忽略重复的数据库,因此不会添加。

    MasterDatabase 是@Database 类(将先前的类与数据库联系起来),并包含一个获取数据库实例的方法,可以从中访问 MasterDao:-

    @Database(
            entities = {MasterDatabaseList.class},
            version = 1
    )
    abstract class MasterDatabase extends RoomDatabase {
        abstract MasterDao getMasterDao();
    
        static volatile MasterDatabase instance = null;
    
        public static MasterDatabase getInstance(Context context) {
            if (instance == null) {
                instance = Room.databaseBuilder(context,MasterDatabase.class,"master.db")
                        .allowMainThreadQueries()
                        .build();
            }
            return instance;
        }
    }
    

    现在是模板数据库,Base???? (用于演示的简单单表数据库)。首先是表 BaseTable @Entity class:-

    @Entity
    class BaseTable {
        @PrimaryKey
        Long id;
        String mydata;
    
        public BaseTable(){}
    
        @Ignore
        public BaseTable(String myData) {
            this.mydata = myData;
        }
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getMydata() {
            return mydata;
        }
    
        public void setMydata(String mydata) {
            this.mydata = mydata;
        }
    }
    
    • 一个非常简单的表,其中包含一个 id 列和一个包含一些字符串数据的列。

    伴随的是@Dao类BaseDao :-

    @Dao
    abstract class BaseDao {
        @Insert
        abstract long insert(BaseTable baseTable);
        @Query("SELECT * FROM basetable")
        abstract List<BaseTable> getAllBaseTables();
        @Update
        abstract int update(BaseTable baseTable);
    }
    
    • 具有非常基本的插入、提取和更新功能

    和之前的 @Database 类 BaseDatabase 一样:-

    @Database(
            entities = {BaseTable.class},
            version = 1
    )
    abstract class BaseDatabase extends RoomDatabase {
        abstract BaseDao getBaseDao();
    
        public static BaseDatabase getInstance(Context context, String databaseName) {
            BaseDatabase instance = null;
            if (databaseName != null) {
                return Room.databaseBuilder(context, BaseDatabase.class, databaseName)
                        .allowMainThreadQueries()
                        .build();
            }
            return instance;
        }
    }
    
    • 注意需要如何传递数据库名称,这基本上是满足多个数据库的关键。

    所有这些都是演示活动。

    public class MainActivity extends AppCompatActivity {
    
        private static final String TAG = "DBINFO";
    
        MasterDatabase masterDB;
        MasterDao masterDao;
    
        /* 3 Lists that need to be synchronised index wise */
        /* i.e. each index position should hold the respective name/databaseobject/dao
        /* List of the known databases (their names) */
        List<MasterDatabaseList> masterDatabaseListList = null;
        /* List of the BaseDatabase objects */
        ArrayList<BaseDatabase> baseDatabaseList = new ArrayList<>();
        /* List of the BaseDao's */
        ArrayList<BaseDao> baseDaoList = new ArrayList<>();
    
        /* The current database */
        int currentBaseIndex = -1; /* Index into the three Lists */
        BaseDatabase currentDB = null;
        BaseDao currentDao = null;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            masterDB = MasterDatabase.getInstance(this);
            masterDao = masterDB.getMasterDao();
            masterDatabaseListList = masterDao.getAllDatabases();
            // Add default db1  if it does not exist
            if (masterDatabaseListList.size() < 1) {
                addBaseDB("db1");
            }
            buildBaseLists();
    
            /* Add some data to db1 IF it exists (it should) */
            setCurrentIndexDBandDao("db1");
            if (currentBaseIndex > -1) {
                currentDao.insert(new BaseTable("Blah for db1"));
            }
    
            /* Add some data to db2 (it will not exist) */
            /* noting that the database will be created if it does not exist */
            setCurrentIndexDBandDao("db2");
            if (currentBaseIndex == -1) {
                addBaseDB("db2");
            }
            if (currentBaseIndex > -1) {
                currentDao.insert(new BaseTable("Blah for db2"));
            }
    
            /* Extract and Log Data for ALL the BaseDatabase databases i.e. db1 and db2 */
            for(MasterDatabaseList masterdb: masterDao.getAllDatabases()) {
                Log.d(TAG,"Database is " + masterdb.getDatabaseName());
                setCurrentIndexDBandDao(masterdb.databaseName);
                if (currentBaseIndex > -1) {
                    for(BaseTable bt: currentDao.getAllBaseTables()) {
                        Log.d(TAG,"Extracted Base Table  row where MyData is" + bt.getMydata());
                    }
                }
            }
        }
    
        /* Add a new Database */
        /* Note that it assumes that it will now be the current */
        /* so the current values are set */
        private void addBaseDB(String baseDBName) {
            masterDao.insert(new MasterDatabaseList(baseDBName));
            buildBaseLists();
            setCurrentIndexDBandDao(baseDBName);
        }
    
        /* Build/ReBuild the 3 Lists according to the master database */
        /* This could be better managed so as to not rebuild existing database/dao objects */
        private void buildBaseLists() {
            int ix = 0;
            baseDatabaseList.clear();
            baseDaoList.clear();
            masterDatabaseListList = masterDao.getAllDatabases();
            // Loop through the databases defined in the master database adding the database and dao to the respective lists
            for (MasterDatabaseList masterDB: masterDao.getAllDatabases()) {
                BaseDatabase baseDB = BaseDatabase.getInstance(this, masterDB.getDatabaseName());
                baseDatabaseList.add(baseDB);
                baseDaoList.add(baseDB.getBaseDao());
                ix++;
            }
        }
    
        /* Set the current trio according to the database name that is:*/
        /*  1.the currentBaseIndex for the 3 Lists */
        /*  2. the BaseDatabase object */
        /*  3. the BaseDao */
        /* The index value (currentBaseIndex) is also returned */
    
        private int setCurrentIndexDBandDao(String baseDBName) {
            currentBaseIndex = getListIndexByBaseDBName(baseDBName);
    
            if (currentBaseIndex > -1) {
                currentDB = baseDatabaseList.get(currentBaseIndex);
                currentDao = baseDaoList.get(currentBaseIndex);
            }
            return currentBaseIndex;
        }
    
        /* Get the index according to the database name passed */
        /* note -1 signifies not know/found */
        private int getListIndexByBaseDBName(String baseDBName) {
            masterDatabaseListList = masterDao.getAllDatabases(); // OverKill????
            int rv = -1; // default to not found
            for(int i=0; i < masterDatabaseListList.size();i++) {
                if (masterDatabaseListList.get(i).databaseName.equals(baseDBName)) {
                    rv = i;
                    break;
                }
            }
            return rv;
        }
    
        /* Output all rows from the BaseTable for data extracted by the BaseDaos getAllBaseTables */
        private void logBaseData(List<BaseTable> baseTableList) {
            Log.d(TAG,"Current Database Index is " + currentBaseIndex + " DB name is " + masterDatabaseListList.get(currentBaseIndex).getDatabaseName());
            for(BaseTable bt: baseTableList) {
                Log.d(TAG,"\tMyData value is " + bt.getMydata());
            }
        }
    }
    

    结果

    第一次运行上述日志时,日志包括:-

    2021-09-16 11:39:30.262 D/DBINFO: Database is db1
    2021-09-16 11:39:30.278 D/DBINFO: Extracted Base Table  row where MyData isBlah for db1
    2021-09-16 11:39:30.278 D/DBINFO: Database is db2
    2021-09-16 11:39:30.284 D/DBINFO: Extracted Base Table  row where MyData isBlah for db2
    

    并通过 Android Studio 的 App Inspector 获取数据库:-

    对于 db2 BaseTable :-

    • 注意 以上只是为了简单地解释使用多个数据库的基础知识,因此代码保持简短。对于要分发的应用程序来说,这可能是不可接受的。

    【讨论】:

    • 这是一个有趣的方法。 MasterDatabase 将管理的数据库有 11 个表。您的最后一条评论似乎表明这可能可行,但可能不实用,对吗?
    • @svstackoverflow 表实体的数量无关紧要或使处理复杂化。相反,结束说明是关于选择/管理方面的,例如每个数据库使用单个实例(单例)以及选择/切换是硬编码而不是用户控制的事实。我也没有处理预先存在的数据库(从资产中复制它)。
    • 感谢您的澄清。我对 Android 和 Room 仍然很陌生,所以我只是在思考最佳实践和选项。我非常感谢您花时间学习这个例子并愿意分享它。
    • 已经有一段时间了,我成功地重新创建了你的例子,所以我会理解它。我想“重构”我现有的应用程序,其中 Room DB (RDB) 有 11 个表。现在我认为 RDB 成为您示例中的“基础”数据库。我有几个问题,但没有其他方法可以问你。 Q1:有 11 个表,有 11 个 DAO。如果我使用 MASTER DB 创建和调用 DB 并且应用程序的其余部分基于 RDB 运行,是否有必要创建和索引 DAO 列表?希望我的问题是有道理的,我的应用程序已经在运行,但这将允许用户创建和重新打开现有的数据库。
    • @svstackoverflow 没有必要。只要你有数据库,你就可以使用适当的 getDao 方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-06
    • 1970-01-01
    • 2020-03-22
    相关资源
    最近更新 更多