如何按月分隔房间数据库?
How to saparate room databases by months?
由于需要按月显示数据,我想制作单独的房间数据库。例如:我需要显示 4 月份的费用,所以我需要导出一个代表 4 月份费用的数据库,并仅将其用于这个月。有什么解决办法吗?这是我的数据库:
Expense.kt
@Entity(tableName = "expenses_table")
data class Expense (
@PrimaryKey(autoGenerate = true)
val id: Int,
val expenseDate: String,
val expenseType: String,
val expenseCost: Int
)
ExpenseDao.kt
@Dao
interface ExpenseDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun addExpense(expense: Expense)
@Query("SELECT * FROM expenses_table ORDER BY id ASC")
fun readAllData(): LiveData<List<Expense>>
}
ExpenseDatabase.kt
@Database(entities = [Expense::class], version = 1, exportSchema = false)
abstract class ExpenseDatabase: RoomDatabase() {
abstract fun expenseDao(): ExpenseDao
companion object {
@Volatile
private var INSTANCE: ExpenseDatabase? = null
fun getDatabase(context: Context): ExpenseDatabase {
val tempInstance = INSTANCE
if (tempInstance != null) {
return tempInstance
}
synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
ExpenseDatabase::class.java,
"expense_table"
).build()
INSTANCE = instance
return instance
}
}
}
}
这不是一个理想的解决方案。即使您找到了解决方案,想象一下一年后您将拥有 12 个不同的数据库。
我会建议你根据需要查询数据库。
I want to make separated room databases due to my needs which is showing the data by months.
需要按月获取数据并不等同于需要有单独的数据库。但是,以下示例仅需要对您的 ExpenseDatabase class 进行一些修改:-
@Database(entities = [Expense::class], version = 1, exportSchema = false)
abstract class ExpenseDatabase: RoomDatabase() {
abstract fun expenseDao(): ExpenseDao
companion object {
@Volatile
private var INSTANCE: ExpenseDatabase? = null
fun getDatabase(context: Context, /* ADDED >>>>>*/yearMonthPrefix: String, /* ADDED >>>>>*/ swap: Boolean = false): ExpenseDatabase {
val tempInstance = INSTANCE
if (tempInstance != null && !swap) {
return tempInstance
}
synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
ExpenseDatabase::class.java,
/* CHANGED >>>>>*/ "${yearMonthPrefix}_expense_table")
.build()
INSTANCE = instance
return instance
}
}
}
}
根据您提供的信息。解决您的问题的最简单且可能最有效的解决方案是拥有一个数据库,其中所有费用都存储在 expenses_table 中,并使用查询来提取当月的费用。
这里的重要因素是 expenseDate column/field 和存储数据格式的适用性。如果您使用 SQLite recognised format,例如 YYYY-MM-DD,则 SQLite Date/Time 函数的格式为 known/understood。
如果是这样,您可以使用以下方法获取当月的 Expense 列表。
@Query("SELECT * FROM expenses_table WHERE strftime('%Y%m',expenseDate) = strftime('%Y%m','now') ORDER BY id ASC")
fun readCurrentMonthsData(): LiveData<List<Expense>>
- 这利用了 SQLite strftime 函数和 now 时间值
以下是您将年和月作为字符串传递的变体,因此可以获得任何年份的任何月份的数据:-
@Query("SELECT * FROM expenses_table WHERE substr(expenseDate,1,7)=:datepart ORDER BY id ASC")
fun readMonthsData(datepart: String): LiveData<List<Expense>>
- 这使用 SQLite substr 函数
演示版
考虑以下内容(.allowMainTrhreadQueries 添加到 buildDatabase 以允许演示使用主线程):-
注意 包含查询(演示版本 return List<Expense>
而不是 LiveData<List<Expense>>
为了方便和简洁)
class MainActivity : AppCompatActivity() {
lateinit var db: ExpenseDatabase
lateinit var dao: ExpenseDao
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = ExpenseDatabase.getDatabase(this, "202201")
dao = db.expenseDao()
dao.addExpenseDemo(Expense(0,"2022-01-01","Type",100))
dao.addExpenseDemo(Expense(0,"2022-01-11","Type",100))
dao.addExpenseDemo(Expense(0,"2022-01-21","Type",100))
dao.addExpenseDemo(Expense(0,"2022-01-31","Type",100))
/* Swap to February Dataabase */
db = ExpenseDatabase.getDatabase(this,"202202",true)
dao = db.expenseDao()
dao.addExpenseDemo(Expense(0,"2022-02-01","Type",100))
dao.addExpenseDemo(Expense(0,"2022-02-02","Type",100))
dao.addExpenseDemo(Expense(0,"2022-02-03","Type",100))
for (e: Expense in dao.readCurrentMonthsDataDemo()) {
Log.d("EXPENSEINFO001","Expense ID is ${e.id} Date is ${e.expenseDate} etc.")
}
/* None will be located as only 2022-02 rows in database */
for (e: Expense in dao.readMonthsDataDemo("2022-01")) {
Log.d("EXPENSEINFO002","Expense ID is ${e.id} Date is ${e.expenseDate} etc.")
}
/* Swap to January Database */
db = ExpenseDatabase.getDatabase(this,"202201", true)
dao = db.expenseDao()
/* None will be located as only 2022-01 rows in database */
for (e: Expense in dao.readCurrentMonthsDataDemo()) {
Log.d("EXPENSEINFO003","Expense ID is ${e.id} Date is ${e.expenseDate} etc.")
}
for (e: Expense in dao.readMonthsDataDemo("2022-01")) {
Log.d("EXPENSEINFO004","Expense ID is ${e.id} Date is ${e.expenseDate} etc.")
}
}
}
演示结果(包含在日志中):-
D/EXPENSEINFO001: Expense ID is 1 Date is 2022-02-01 etc.
D/EXPENSEINFO001: Expense ID is 2 Date is 2022-02-02 etc.
D/EXPENSEINFO001: Expense ID is 3 Date is 2022-02-03 etc.
D/EXPENSEINFO004: Expense ID is 1 Date is 2022-01-01 etc.
D/EXPENSEINFO004: Expense ID is 2 Date is 2022-01-11 etc.
D/EXPENSEINFO004: Expense ID is 3 Date is 2022-01-21 etc.
D/EXPENSEINFO004: Expense ID is 4 Date is 2022-01-31 etc.
通过 App Inspection 的数据库:-
并通过设备文件资源管理器:-
请注意,虽然每个实际的数据库文件只有 4k,但 -wal 文件中的数据将被应用(不是全部,但至少 12K(每个 [=91= 至少 4K ])).因此,多个数据库文件将浪费相对大量的文件 space 每个数据库。
交换数据库也会产生额外的开销。
由于需要按月显示数据,我想制作单独的房间数据库。例如:我需要显示 4 月份的费用,所以我需要导出一个代表 4 月份费用的数据库,并仅将其用于这个月。有什么解决办法吗?这是我的数据库:
Expense.kt
@Entity(tableName = "expenses_table")
data class Expense (
@PrimaryKey(autoGenerate = true)
val id: Int,
val expenseDate: String,
val expenseType: String,
val expenseCost: Int
)
ExpenseDao.kt
@Dao
interface ExpenseDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun addExpense(expense: Expense)
@Query("SELECT * FROM expenses_table ORDER BY id ASC")
fun readAllData(): LiveData<List<Expense>>
}
ExpenseDatabase.kt
@Database(entities = [Expense::class], version = 1, exportSchema = false)
abstract class ExpenseDatabase: RoomDatabase() {
abstract fun expenseDao(): ExpenseDao
companion object {
@Volatile
private var INSTANCE: ExpenseDatabase? = null
fun getDatabase(context: Context): ExpenseDatabase {
val tempInstance = INSTANCE
if (tempInstance != null) {
return tempInstance
}
synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
ExpenseDatabase::class.java,
"expense_table"
).build()
INSTANCE = instance
return instance
}
}
}
}
这不是一个理想的解决方案。即使您找到了解决方案,想象一下一年后您将拥有 12 个不同的数据库。
我会建议你根据需要查询数据库。
I want to make separated room databases due to my needs which is showing the data by months.
需要按月获取数据并不等同于需要有单独的数据库。但是,以下示例仅需要对您的 ExpenseDatabase class 进行一些修改:-
@Database(entities = [Expense::class], version = 1, exportSchema = false)
abstract class ExpenseDatabase: RoomDatabase() {
abstract fun expenseDao(): ExpenseDao
companion object {
@Volatile
private var INSTANCE: ExpenseDatabase? = null
fun getDatabase(context: Context, /* ADDED >>>>>*/yearMonthPrefix: String, /* ADDED >>>>>*/ swap: Boolean = false): ExpenseDatabase {
val tempInstance = INSTANCE
if (tempInstance != null && !swap) {
return tempInstance
}
synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
ExpenseDatabase::class.java,
/* CHANGED >>>>>*/ "${yearMonthPrefix}_expense_table")
.build()
INSTANCE = instance
return instance
}
}
}
}
根据您提供的信息。解决您的问题的最简单且可能最有效的解决方案是拥有一个数据库,其中所有费用都存储在 expenses_table 中,并使用查询来提取当月的费用。
这里的重要因素是 expenseDate column/field 和存储数据格式的适用性。如果您使用 SQLite recognised format,例如 YYYY-MM-DD,则 SQLite Date/Time 函数的格式为 known/understood。
如果是这样,您可以使用以下方法获取当月的 Expense 列表。
@Query("SELECT * FROM expenses_table WHERE strftime('%Y%m',expenseDate) = strftime('%Y%m','now') ORDER BY id ASC")
fun readCurrentMonthsData(): LiveData<List<Expense>>
- 这利用了 SQLite strftime 函数和 now 时间值
以下是您将年和月作为字符串传递的变体,因此可以获得任何年份的任何月份的数据:-
@Query("SELECT * FROM expenses_table WHERE substr(expenseDate,1,7)=:datepart ORDER BY id ASC")
fun readMonthsData(datepart: String): LiveData<List<Expense>>
- 这使用 SQLite substr 函数
演示版
考虑以下内容(.allowMainTrhreadQueries 添加到 buildDatabase 以允许演示使用主线程):-
注意 包含查询(演示版本 return List<Expense>
而不是 LiveData<List<Expense>>
为了方便和简洁)
class MainActivity : AppCompatActivity() {
lateinit var db: ExpenseDatabase
lateinit var dao: ExpenseDao
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = ExpenseDatabase.getDatabase(this, "202201")
dao = db.expenseDao()
dao.addExpenseDemo(Expense(0,"2022-01-01","Type",100))
dao.addExpenseDemo(Expense(0,"2022-01-11","Type",100))
dao.addExpenseDemo(Expense(0,"2022-01-21","Type",100))
dao.addExpenseDemo(Expense(0,"2022-01-31","Type",100))
/* Swap to February Dataabase */
db = ExpenseDatabase.getDatabase(this,"202202",true)
dao = db.expenseDao()
dao.addExpenseDemo(Expense(0,"2022-02-01","Type",100))
dao.addExpenseDemo(Expense(0,"2022-02-02","Type",100))
dao.addExpenseDemo(Expense(0,"2022-02-03","Type",100))
for (e: Expense in dao.readCurrentMonthsDataDemo()) {
Log.d("EXPENSEINFO001","Expense ID is ${e.id} Date is ${e.expenseDate} etc.")
}
/* None will be located as only 2022-02 rows in database */
for (e: Expense in dao.readMonthsDataDemo("2022-01")) {
Log.d("EXPENSEINFO002","Expense ID is ${e.id} Date is ${e.expenseDate} etc.")
}
/* Swap to January Database */
db = ExpenseDatabase.getDatabase(this,"202201", true)
dao = db.expenseDao()
/* None will be located as only 2022-01 rows in database */
for (e: Expense in dao.readCurrentMonthsDataDemo()) {
Log.d("EXPENSEINFO003","Expense ID is ${e.id} Date is ${e.expenseDate} etc.")
}
for (e: Expense in dao.readMonthsDataDemo("2022-01")) {
Log.d("EXPENSEINFO004","Expense ID is ${e.id} Date is ${e.expenseDate} etc.")
}
}
}
演示结果(包含在日志中):-
D/EXPENSEINFO001: Expense ID is 1 Date is 2022-02-01 etc.
D/EXPENSEINFO001: Expense ID is 2 Date is 2022-02-02 etc.
D/EXPENSEINFO001: Expense ID is 3 Date is 2022-02-03 etc.
D/EXPENSEINFO004: Expense ID is 1 Date is 2022-01-01 etc.
D/EXPENSEINFO004: Expense ID is 2 Date is 2022-01-11 etc.
D/EXPENSEINFO004: Expense ID is 3 Date is 2022-01-21 etc.
D/EXPENSEINFO004: Expense ID is 4 Date is 2022-01-31 etc.
通过 App Inspection 的数据库:-
并通过设备文件资源管理器:-
请注意,虽然每个实际的数据库文件只有 4k,但 -wal 文件中的数据将被应用(不是全部,但至少 12K(每个 [=91= 至少 4K ])).因此,多个数据库文件将浪费相对大量的文件 space 每个数据库。
交换数据库也会产生额外的开销。