kotlin 是否可以使用sqldelight从本地资源加载预填充的数据库

imzjd6km  于 2023-08-06  发布在  Kotlin
关注(0)|答案(4)|浏览(142)

我有一个相对较大的数据库,可能需要1到2分钟来初始化,是否可以在使用sqldelight(Kotlin多平台)时加载预填充的数据库,而不是在应用程序启动时初始化数据库?

ie3xauqp

ie3xauqp1#

对不起,我还不能添加任何评论,这将是更合适的。
虽然没有直接回答你的问题,但1到2分钟对sqlite来说真的很长。你在干什麽?我首先要确保你正确地使用了交易。1-2分钟的插入数据将(可能)导致一个巨大的db文件。
或者,我的问题,由于我不得不使用一个预填充的数据库是与大尺寸的.sq文件(超过30 MB的文本插入每个表),和SqlDeLight默默地中断生成,没有显示错误消息。
在初始化sqldelight之前,你需要将db文件放在android上的assets和iOS上的bundle中,并将它们复制到各自的文件夹中。
从android和ios的资源中加载数据库感觉工作量很大,这意味着共享项目不是唯一初始化数据的地方。
Kotlin多平台库Moko-resources解决了共享模块中数据库的单一源的问题。KMM的工作方式与Android和iOS相同。
不幸的是,使用这个功能几乎没有在库的样本中提出。我在预期的DatabaseDriverFactory类中添加了第二个方法(getDriver)以打开准备好的数据库,并在平台上实现了它。例如,对于androidMain:

actual class DatabaseDriverFactory(private val context: Context) {
    actual fun createDriver(schema: SqlDriver.Schema, fileName: String): SqlDriver {
        return AndroidSqliteDriver(schema, context, fileName)
    }

    actual fun getDriver(schema: SqlDriver.Schema, fileName: String): SqlDriver {
        val database: File = context.getDatabasePath(fileName)

        if (!database.exists()) {
            val inputStream = context.resources.openRawResource(MR.files.dbfile.rawResId)
            val outputStream = FileOutputStream(database.absolutePath)

            inputStream.use { input: InputStream ->
                outputStream.use { output: FileOutputStream ->
                    input.copyTo(output)
                }
            }
        }

        return AndroidSqliteDriver(schema, context, fileName)
    }
}

字符串
fullDb是库生成的类的FileResource,它与位于commonMain模块的resources/MR/files目录中的文件名相关联。其属性rawResId表示平台端资源ID。

6ss1mwsb

6ss1mwsb2#

是的,但这很棘手。不仅仅是“多平台”。在尝试初始化sqldelight之前,您需要将db复制到db文件夹。这可能意味着当应用程序启动时,主线程上的i/o。
现在没有标准的方法来做到这一点。在初始化sqldelight之前,你需要将db文件放在android上的assets和iOS上的bundle中,并将它们复制到各自的文件夹中。显然,您需要首先检查数据库是否存在,或者通过某种方式知道这是您第一次运行应用程序。
如果您计划发布包含较新数据库的更新,则需要管理版本,而不仅仅是检查数据库的存在。
虽然没有直接回答你的问题,但1到2分钟对sqlite来说真的很长。你在干什麽?我首先要确保你正确地使用了交易。1-2分钟的插入数据将(可能)导致一个巨大的db文件。

ma8fv8wu

ma8fv8wu3#

您唯一需要做的就是使用驱动程序指定DB文件的路径。
假设您的数据库位于/mnt/my_best_app_dbs/super.db中。现在,在Driver的name属性中传递路径。大概是这样的:

val sqlDriver: SqlDriver = AndroidSqliteDriver(Schema, context, "/mnt/my_best_app_dbs/best.db")

字符串
请记住,您可能需要具有允许您读取给定存储类型的权限。

icnyk63a

icnyk63a4#

我已经将@Denis Luttcev的代码转换为ios目标端,它在我的Kotlin多平台项目中完美地工作。有一些麻烦弄清楚如何使它的工作,所以在情况下,其他人将需要它这里是我得到的:

actual class DriverFactory {
    actual fun createDriver(schema: SqlDriver.Schema, fileName: String): SqlDriver {
        val fileManager = NSFileManager.defaultManager
        val documentsPath = NSSearchPathForDirectoriesInDomains(
            directory = NSApplicationSupportDirectory,
            domainMask = NSUserDomainMask,
            expandTilde = true
        ).first() as NSString

        val dbDirectoryPath = documentsPath.stringByAppendingPathComponent("databases")
        val targetDbPath = documentsPath.stringByAppendingPathComponent("databases/$fileName")
        val sourceDbPath = MR.files.dbfile.path

        val directoryExists = fileManager.fileExistsAtPath(dbDirectoryPath)
        val databaseExists = fileManager.fileExistsAtPath(targetDbPath)

        if (databaseExists.not()) {
            memScoped {
                // you can use it to log errors
                val error: ObjCObjectVar<NSError?> = alloc()

                if (directoryExists.not()) {
                    val createSuccess = fileManager.createDirectoryAtPath(
                        path = dbDirectoryPath,
                        withIntermediateDirectories = true,
                        attributes = null,
                        error = error.ptr
                    )
                }

                val copySuccess = fileManager.copyItemAtPath(
                    srcPath = sourceDbPath,
                    toPath = targetDbPath,
                    error = error.ptr
                )
            }
        }

        return NativeSqliteDriver(schema, fileName)
    }
}

字符串

相关问题