Room - ไดเร็กทอรีการเอ็กซ์พอร์ต Schema ไม่ได้ถูกจัดเตรียมไว้ในตัวประมวลผลหมายเหตุประกอบดังนั้นเราไม่สามารถเอ็กซ์พอร์ตสกีมา


350

ฉันใช้ห้องส่วนประกอบฐานข้อมูล Android

ฉันได้กำหนดค่าทุกอย่างแล้ว แต่เมื่อฉันคอมไพล์ Android Studio ให้คำเตือนนี้กับฉัน:

ไดเร็กทอรีการส่งออกสคีมาไม่ได้ถูกจัดเตรียมไว้ในตัวประมวลผลคำอธิบายประกอบดังนั้นเราจึงไม่สามารถส่งออกสคีมาได้ คุณสามารถระบุ room.schemaLocationอาร์กิวเมนต์ตัวประมวลผลคำอธิบายประกอบหรือตั้งค่า exportSchema เป็นเท็จ

เพราะฉันเข้าใจว่ามันเป็นที่ตั้งของไฟล์ฐานข้อมูล

มันจะส่งผลกระทบต่อแอพของฉันได้อย่างไร การปฏิบัติที่ดีที่สุดที่นี่คืออะไร? ฉันควรใช้ตำแหน่งเริ่มต้น ( falseค่า) หรือไม่

คำตอบ:


396

ตามเอกสาร :

คุณสามารถตั้งค่าอาร์กิวเมนต์ตัวประมวลผลคำอธิบายประกอบ (room.schemaLocation) ให้บอก Room เพื่อส่งออก schema ไปยังโฟลเดอร์ แม้ว่าจะไม่ได้บังคับ แต่เป็นวิธีที่ดีที่จะมีประวัติรุ่นใน codebase ของคุณและคุณควรส่งไฟล์นั้นไปยังระบบควบคุมเวอร์ชันของคุณ (แต่ไม่ต้องจัดส่งด้วยแอพของคุณ!)

ดังนั้นหากคุณไม่จำเป็นต้องตรวจสอบสคีมาและคุณต้องการกำจัดคำเตือนให้เพิ่มexportSchema = falseของคุณRoomDatabaseดังต่อไปนี้

@Database(entities = { YourEntity.class }, version = 1, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
   //...
}

หากคุณปฏิบัติตามคำตอบ @mikejonesguy ด้านล่างคุณจะต้องปฏิบัติตามแนวปฏิบัติที่ดีที่กล่าวถึงในเอกสาร :) โดยทั่วไปคุณจะได้รับ.jsonไฟล์ใน../app/schemas/โฟลเดอร์ของคุณ และมันก็เป็นแบบนี้:

{
  "formatVersion": 1,
  "database": {
    "version": 1,
    "identityHash": "53db508c5248423325bd5393a1c88c03",
    "entities": [
      {
        "tableName": "sms_table",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `message` TEXT, `date` INTEGER, `client_id` INTEGER)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER"
          },
          {
            "fieldPath": "message",
            "columnName": "message",
            "affinity": "TEXT"
          },
          {
            "fieldPath": "date",
            "columnName": "date",
            "affinity": "INTEGER"
          },
          {
            "fieldPath": "clientId",
            "columnName": "client_id",
            "affinity": "INTEGER"
          }
        ],
        "primaryKey": {
          "columnNames": [
            "id"
          ],
          "autoGenerate": true
        },
        "indices": [],
        "foreignKeys": []
      }
    ],
    "setupQueries": [
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"53db508c5248423325bd5393a1c88c03\")"
    ]
  }
}

หากความเข้าใจของฉันถูกต้องคุณจะได้รับไฟล์ดังกล่าวพร้อมกับการอัพเดททุกเวอร์ชันของฐานข้อมูลเพื่อให้คุณสามารถติดตามประวัติของฐานข้อมูลได้อย่างง่ายดาย


8
หมายความว่าอย่างไร "อย่าส่งพร้อมแอพของคุณ" มันจะรวมอยู่ใน APK?
Jongz Puangput

2
หากติดตาม "ไม่จัดส่งพร้อมกับแอปของคุณ" ฉันควรลบไฟล์ JSON ก่อนสร้าง APK หรือไม่
ภาพลวงตา

8
"ไม่จัดส่งพร้อมกับแอปของคุณ" หมายถึง "อย่าตั้งค่า schemaLocation เป็น 'app / res / raw' ตั้งค่า schemaLocation เป็นไดเรกทอรีที่ไม่รวมอยู่ใน APK"
galcyurio

3
@galcyurio $ projectDir / schemas เป็นไดเรกทอรีจาก APK ใช่ไหม ฉันสำรวจ APK ที่สร้างขึ้นแล้วและไม่เห็นตรงนั้น แม้ว่าฉันจะเห็น / res (ซึ่งบัญชีสำหรับ app / src / main / res) ตัวอย่างเช่น
xarlymg89

1
@glucaio ฉันสำรวจ APK (และแอปมัดด้วย) และไม่พบมัน ดังนั้นฉันเชื่อว่าเราปลอดภัย
xarlymg89

390

ในbuild.gradleไฟล์สำหรับโมดูลแอปของคุณให้เพิ่มส่วนนี้ลงในdefaultConfigส่วน (ใต้androidส่วน) สิ่งนี้จะเขียนสคีมาลงในschemasโฟลเดอร์ย่อยของโฟลเดอร์โครงการของคุณ

javaCompileOptions {
    annotationProcessorOptions {
        arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
    }
}

แบบนี้:

// ...

android {

    // ... (compileSdkVersion, buildToolsVersion, etc)

    defaultConfig {

        // ... (applicationId, miSdkVersion, etc)

        javaCompileOptions {
            annotationProcessorOptions {
                arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
            }
        }
    }

    // ... (buildTypes, compileOptions, etc)

}

// ...

35
หากใครสงสัยวิธีนี้ใช้ได้กับ Kotlin เมื่อใช้kapt
DanielDiSu

1
เราควร gitignore ไฟล์ json ที่สร้างในapp/schemasไดเรกทอรีโดยการดำเนินการนี้ apkและข้าพเจ้าได้ยินเราควรใส่คีมาลงในไดเรกทอรีที่ไม่ได้รวมอยู่ในนั้น เราจะทำสิ่งนั้นได้อย่างไร
ravi

2
@ravi ไฟล์ schema ที่สร้างขึ้นควรเก็บไว้ในการควบคุมเวอร์ชันเนื่องจาก Room ถูกใช้เพื่อตรวจสอบการเปลี่ยนแปลงและช่วยให้แน่ใจว่าการเปลี่ยนแปลงฐานข้อมูลที่คุณอัพเดตเวอร์ชันฐานข้อมูลและสร้างแผนการโอนย้าย
appmattus

1
การกำหนดค่านี้มีผลต่อรุ่นที่วางจำหน่ายหรือไม่? ฉันหมายถึงเมื่อฉันส่งออกโครงการไปยังแอปที่วางจำหน่าย
Anargu

หากผลลัพธ์นี้เป็นข้อผิดพลาด: ไม่พบเมธอด annotationProcessorOptions () เพื่อหาข้อโต้แย้งตรวจสอบคำตอบของ Luna ด้านล่าง: stackoverflow.com/a/54366985/1617737
ban-geoengineering

185

Kotlin? ไปเลย:

android {

    // ... (compileSdkVersion, buildToolsVersion, etc)

    defaultConfig {

        // ... (applicationId, miSdkVersion, etc)

        kapt {
            arguments {
                arg("room.schemaLocation", "$projectDir/schemas")
            }
        }
    }

    buildTypes {
        // ... (buildTypes, compileOptions, etc)
    }
}

//...

อย่าลืมเกี่ยวกับปลั๊กอิน:

apply plugin: 'kotlin-kapt'

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับตัวประมวลผลคำอธิบายประกอบของ kotlin โปรดไปที่: เอกสารของ Kotlin


เช่นเดียวกับที่คุณตอบ: D
theapache64

12

คำตอบข้างต้นถูกต้อง รุ่นนี้ง่ายต่อการติดตาม:

เนื่องจาก "ไดเรกทอรีการส่งออก Schema ไม่ได้ถูกจัดเตรียมไว้ในตัวประมวลผลคำอธิบายประกอบ" ดังนั้นเราจึงจำเป็นต้องจัดเตรียมไดเรกทอรีสำหรับการส่งออก Schema:

ขั้นตอน [1] ในไฟล์ของคุณซึ่งขยาย RoomDatabase ให้เปลี่ยนบรรทัดเป็น:

`@Database(entities = ???.class,version = 1, exportSchema = true)`

หรือ

`@Database(entities = ???.class,version = 1)` 

(เนื่องจากค่าเริ่มต้นเป็นจริงเสมอ)

ขั้นตอน [2] ในไฟล์ build.gradle (โครงการ: ????) ของคุณในdefaultConfig {} (ซึ่งอยู่ในandroid {}ส่วนใหญ่) ให้เพิ่มส่วนjavaCompileOptions {}มันจะเป็นดังนี้:

         android{
                defaultConfig{
                      //javaComplieOptions SECTION
                      javaCompileOptions {
                            annotationProcessorOptions {
                                     arguments = ["room.schemaLocation":"$projectDir/schemas".toString()]
                            }
                       }
                      //Other SECTION
                      ...
                }
         }

$ projectDir : เป็นชื่อตัวแปรคุณไม่สามารถเปลี่ยนได้ มันจะได้รับไดเรกทอรีโครงการของคุณเอง

สกีมา : เป็นสตริงคุณสามารถเปลี่ยนเป็นสิ่งที่คุณต้องการ ตัวอย่างเช่น: "$projectDir/MyOwnSchemas".toString()


ในขั้นตอน [2], คุณแน่ใจหรือว่ามันเป็นbuild.gradle(project:????)และไม่ได้build.gradle(app:????)?
Ace

9

@mikejonesguy คำตอบนั้นสมบูรณ์แบบในกรณีที่คุณวางแผนที่จะทดสอบการย้ายห้อง (แนะนำ) ให้เพิ่มตำแหน่งสคีมาลงในชุดซอร์ส

ในไฟล์ build.gradle ของคุณคุณระบุโฟลเดอร์เพื่อวางไฟล์ JSON สกีมาที่สร้างขึ้นเหล่านี้ เมื่อคุณอัปเดตสคีมาคุณจะพบไฟล์ JSON หลายไฟล์หนึ่งไฟล์สำหรับทุกเวอร์ชัน ตรวจสอบให้แน่ใจว่าคุณยอมรับทุกไฟล์ที่สร้างขึ้นเพื่อควบคุมแหล่งที่มา ครั้งต่อไปที่คุณเพิ่มหมายเลขเวอร์ชันอีกครั้ง Room จะสามารถใช้ไฟล์ JSON สำหรับการทดสอบได้

build.gradle

android {

    // [...]

    defaultConfig {

        // [...]

        javaCompileOptions {
            annotationProcessorOptions {
                arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
            }
        }
    }

    // add the schema location to the source sets
    // used by Room, to test migrations
    sourceSets {
        androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
    }

    // [...]
}

3

ฉันใช้.ktsไฟล์ Gradle (Kotlin Gradle DSL) และkotlin-kaptปลั๊กอิน แต่ฉันยังคงได้รับข้อผิดพลาดในการรวบรวมสคริปต์เมื่อฉันใช้คำตอบของ Ivanov Maksim

Unresolved reference: kapt

สำหรับฉันนี่เป็นสิ่งเดียวที่ทำงาน:

android {
    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = mapOf("room.schemaLocation" to "$projectDir/schemas")
            }
        }
    }
}

ไม่มีอะไรทำงานให้ฉันด้วย ฉันกำลังใช้ Kotlin
nyxee

0

อาจเป็นไปได้ว่าคุณไม่ได้เพิ่มระดับห้องของคุณให้กับชั้นเด็กRoomDatabaseเล็ก@Database(entities = {your_classes})

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.