ห้องไม่สามารถตรวจสอบความสมบูรณ์ของข้อมูลได้


94

ฉันได้รับข้อผิดพลาดนี้ขณะใช้งานโปรแกรมกับ Room Database

Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number. 
You can simply fix this by increasing the version number.

ดูเหมือนว่าเราจำเป็นต้องอัปเดตเวอร์ชันของฐานข้อมูล แต่เราสามารถทำได้จากที่ใดในห้อง?


2
หากคุณไม่สนใจข้อมูลของแอปการลบเนื้อหาทั้งหมดออกจากการตั้งค่าแอปพลิเคชันอาจช่วยได้เช่นกันเนื่องจากจะทำลายฐานข้อมูลทั้งหมด
O-9

คำตอบ:


131

เมื่อคุณพบข้อความนี้เป็นครั้งแรกคุณมักจะทำงานกับฐานข้อมูลเวอร์ชันที่ยังไม่ได้เผยแพร่ หากเป็นกรณีที่มีโอกาสมากที่สุดที่คุณไม่ควรเพิ่มรุ่นฐานข้อมูล เพียงแค่ล้างข้อมูลแอพจะย้ายคุณผ่านข้อยกเว้น

หากคุณไม่เพิ่มฐานข้อมูล (แนะนำ):

คุณควรล้างข้อมูลแอพของแอพจากการตั้งค่า Android หรือคุณอาจถอนการติดตั้งแอปเวอร์ชันก่อนหน้าแล้วติดตั้งเวอร์ชันใหม่เพื่อให้ผ่านข้อยกเว้นได้ แนวทางหลังนี้ใช้ไม่ได้ภายใต้เงื่อนไขบางประการ (เช่นเมื่อเปิดใช้งานอนุญาตการสำรองข้อมูล)

เนื่องจากการล้างข้อมูลแอปพลิเคชันได้ผลเสมอฉันจึงใช้เส้นทางนั้นทุกครั้ง

หากคุณเพิ่มเวอร์ชันฐานข้อมูล:

คุณจะต้องเขียนรหัสการย้ายฐานข้อมูลเพื่อรองรับการเปลี่ยนแปลงใด ๆ ในสคีมาฐานข้อมูล ดูที่นี่สำหรับข้อมูลเกี่ยวกับการโยกย้าย

ทางเลือกในการเขียนรหัสการย้ายฐานข้อมูลคือการเรียกfallbackToDestructiveMigrationใช้ตัวสร้างฐานข้อมูล Room นี่คงไม่ใช่ความคิดที่ดี การลืมลบสายนี้และลืมอัพเกรดฐานข้อมูลจะทำให้ข้อมูลสูญหาย

// Using this fallback is almost certainly a bad idea
Database database = Room.databaseBuilder(context, Database.class, DATABASE_NAME)
        .fallbackToDestructiveMigration()
        .build();

อีกครั้งค่าการเพิ่มฐานข้อมูลรุ่นหรือตกกลับในการโยกย้ายทำลายเป็นสิ่งจำเป็นหากคีมาฐานข้อมูลก่อนหน้านี้ไม่ได้มีชีวิตอยู่ในป่า


4
ฉันหวังว่าพวกเขาจะรวมวิธีทางเลือกอื่นสำหรับกรณีนี้ :(
BoD

3
ในเวอร์ชัน1.0.0-rc1Room สิ่งเดียวที่ใช้ได้ผลสำหรับฉันคือการเพิ่มเวอร์ชันฐานข้อมูล
Dick Lucas

42
ฉันมี android: allowBackup = "true" ใน AndroidManifest.xml ซึ่งทำให้ไม่สามารถล้างข้อมูลได้แม้ว่าจะถอนการติดตั้งแอปแล้วก็ตาม ฉันตั้งค่าแอตทริบิวต์นี้เป็นเท็จแล้วติดตั้งแอปใหม่ซึ่งช่วยในการกำจัดปัญหา โปรดทราบว่า true เป็นค่าเริ่มต้นสำหรับ allowBackup ดังนั้นหากคุณไม่ได้ใช้เลยค่านี้อาจทำให้ข้อมูลยังคงอยู่
Bartek

1
@Bartek ความคิดเห็นนี้สมควรเป็นคำตอบแล้ว
guness

คำอธิบาย! ฉันถอนการติดตั้งแอปครั้งแล้วครั้งเล่าเพราะเหตุใดจึงอัปเกรดเวอร์ชันที่อยู่ระหว่างการพัฒนา โอ้ไม่เคยคิดมาก่อนว่าการล้างข้อมูลจากการตั้งค่าเป็นกุญแจสำคัญในอนาคต คำตอบที่ดี ควรเป็นทางออกที่ได้รับการยอมรับ
sud007

29

ตามค่าเริ่มต้นของรายการ Android android:allowBackup="true"ซึ่งอนุญาตให้แอปยังคงมี SQLite DB เมื่อติดตั้งใหม่

สมมติว่าDATABASE_VERSIONตอนแรกของคุณคือ 3 แล้วคุณตัดสินใจลดเวอร์ชัน DB จาก 3 เป็น 1

@Database(entities = {CallRecording.class}, version = DATABASE_VERSION)
public abstract class AppDatabase extends RoomDatabase {
    public abstract RecordingDAO recordingDAO();

//    static final Migration MIGRATION_1_2 = new Migration(1, 2) {
//        @Override
//        public void migrate(SupportSQLiteDatabase database) {
//            // Since we didn't alter the table, there's nothing else to do here.
//        }
//    };
}

คุณสามารถบรรลุได้เช่นนี้

  • ล้างข้อมูลแอพจากการตั้งค่า การดำเนินการนี้จะลบ DB รุ่นเก่า (DATABASE_VERSION = 3) ออกจากโทรศัพท์
  • ถอนการติดตั้งแอพของคุณ
  • ลด DATABASE_VERSION เวอร์ชันเป็น 1
  • สร้างและติดตั้งแอปของคุณใหม่

เป็นแนวทางปฏิบัติที่ดีที่จะรักษาให้DATABASE_VERSIONคงที่


1
จะไม่ส่งผลกระทบต่อผู้ใช้ที่จะอัปเดตแอปจาก play store หรือไม่?
nimi0112

1
ฉันทำตามวิธีเดียวกัน แต่ไม่ได้ผล แม้ว่าฉันจะพยายามติดตั้งบนอุปกรณ์ใหม่จาก Android Studio แต่ก็แสดงข้อผิดพลาดเดียวกัน: x
Sadat

@ nimi0112 สำหรับตัวแปรรุ่นของคุณคุณควรอนุญาตการสำรองข้อมูลอย่างไรก็ตามสำหรับตัวแปรดีบักของคุณคุณสามารถปิดได้
Chad Mx

25

android: allowBackup = "true" ภายใน AndroidManifest.xml ป้องกันไม่ให้ล้างข้อมูลแม้ว่าจะถอนการติดตั้งแอปแล้วก็ตาม

เพิ่มสิ่งนี้ในรายการของคุณ:

android:allowBackup="false"

และติดตั้งแอปใหม่

หมายเหตุ: ตรวจสอบให้แน่ใจว่าคุณได้เปลี่ยนกลับเป็นจริงในภายหลังหากคุณต้องการสำรองข้อมูลอัตโนมัติ

วิธีแก้ปัญหาอื่น:

ตรวจสอบ identityHash ของไฟล์ json เก่าของคุณและไฟล์ json ใหม่ในโฟลเดอร์ apps \ schema

หาก identityHash แตกต่างกันก็จะให้ข้อผิดพลาดนั้น ค้นหาสิ่งที่คุณเปลี่ยนแปลงโดยการเปรียบเทียบไฟล์ json ทั้งสองไฟล์หากคุณไม่ต้องการเปลี่ยนแปลงอะไร

ตรวจสอบว่าคุณมี exportSchema = true

@Database(entities = {MyEntity.class, ...}, version = 2, exportSchema = true)

ไฟล์สคีมา json:

  "formatVersion": 1,
  "database": {
    "version": 2,
    "identityHash": "53cc5ef34d2ebd33c8518d79d27ed012",
    "entities": [
      {

รหัส:

private void checkIdentity(SupportSQLiteDatabase db) {
    String identityHash = null;
    if (hasRoomMasterTable(db)) {
        Cursor cursor = db.query(new SimpleSQLiteQuery(RoomMasterTable.READ_QUERY));
        //noinspection TryFinallyCanBeTryWithResources
        try {
            if (cursor.moveToFirst()) {
                identityHash = cursor.getString(0);
            }
        } finally {
            cursor.close();
        }
    }
    if (!mIdentityHash.equals(identityHash) && !mLegacyHash.equals(identityHash)) {
        throw new IllegalStateException("Room cannot verify the data integrity. Looks like"
                + " you've changed schema but forgot to update the version number. You can"
                + " simply fix this by increasing the version number.");
    }
}

20

คำตอบของAniruddh Pariharทำให้ฉันมีคำใบ้และแก้ไขได้

RoomDatabaseค้นหาสำหรับการเรียนที่คุณได้ขยาย คุณจะพบเวอร์ชันดังต่อไปนี้:

@Database(entities = {YourEntity.class}, version = 1)

เพียงแค่เพิ่มเวอร์ชันและปัญหาจะได้รับการแก้ไข


11

มันง่ายมากดังที่แสดงในบันทึก

Looks like you've changed schema but forgot to update the Database version number. 
You can simply fix this by increasing the version number.

ไปที่คลาสเวอร์ชันฐานข้อมูลของคุณและอัปเกรดเวอร์ชัน DB ของคุณโดยเพิ่ม 1 จากปัจจุบัน

ตัวอย่างเช่นค้นหาคำอธิบายประกอบ @Database ในโครงการของคุณดังด้านล่าง

@Database(entities = {YourEntityName.class}, version = 1)

ที่นี่เวอร์ชัน = 1 คือเวอร์ชันฐานข้อมูลคุณต้องเพิ่มทีละรายการนั่นคือมัน


1
ใช่ฉันได้รับข้อผิดพลาดนั่นคือเหตุผลที่ฉันได้กล่าวถึงในคำถามนั้นIt seems we need to update database versionด้วย แต่ฉันไม่เข้าใจว่าเวอร์ชันนั้นถูกกล่าวถึง ยังไงก็ตามขอบคุณสำหรับคำใบ้นั้น
ราวี

คุณได้เปลี่ยนข้อความแสดงข้อผิดพลาด แต่ไม่ได้ให้ข้อมูลเพิ่มเติมใด ๆ เพื่อแก้ไขความสับสนของผู้โพสต์ต้นฉบับ
Carl Rossman

@CarlRossman: คุณต้องพบคลาสฐานข้อมูลของคุณในโครงการของคุณที่คุณใช้คำอธิบายประกอบฐานข้อมูลในชั้นเรียนนั้นคุณจะพบเวอร์ชันฐานข้อมูล (ค่าจำนวนเต็ม) เพียงแค่เพิ่มขึ้นทีละรายการจากปัจจุบัน
Aniruddh Parihar

7

1: - ดูเหมือนว่าเราจำเป็นต้องอัปเดตเวอร์ชันฐานข้อมูล (เพิ่มทีละ 1)

ป้อนคำอธิบายภาพที่นี่

ครั้งที่ 2 ถอนการติดตั้งแอพหรือล้างข้อมูลแอพ


6

บนโทรศัพท์ Android:

ถอนการติดตั้งแอพหรือล้างข้อมูลแอพ

ในการลบข้อมูลแอพ: ไปที่การตั้งค่า -> แอพ -> เลือกแอพของคุณ -> ที่เก็บข้อมูล -> ล้างข้อมูล

การถอนการติดตั้ง (และติดตั้งใหม่) ใช้ไม่ได้ในทุกกรณีดังนั้นลองล้างข้อมูลก่อน!


ใช่ว่าได้ผล แต่น่าแปลกที่ฉันได้รับปัญหานี้บนอุปกรณ์ที่ลบไปทั้งหมดและตั้งค่าใหม่เมื่อครู่นี้ แต่เพียงแค่ล้างข้อมูลที่แก้ไขได้
Ajith Memana

สิ่งนี้ไม่ควรทำในการผลิต คุณไม่ควรบังคับให้ผู้ใช้ของคุณทั้งหมดล้างข้อมูลจากแอป เขียนรหัสการย้ายข้อมูลได้ดีกว่าโดยการเพิ่มเวอร์ชันทีละ 1 ในฐานข้อมูลห้องของคุณ
Rajeev Jayaswal

5

ในกรณีของฉันandroid:allowBackup="false"ทำให้มันใช้งานได้จริงเป็นเท็จเนื่องจากสิ่งนี้ทำให้ฉันฝันร้ายมาก่อนเช่นกันนี่เป็นสิ่งที่แปลกที่สุดว่าทำไมการตั้งค่านี้จึงเปิดใช้งานโดยค่าเริ่มต้น!


5

ในการแก้ไขปัญหาใน kotlin:

อันดับแรก

@Database(entities = [Contact::class], version = 2)

ประการที่สอง

val MIGRATION_1_2 = object : Migration(1, 2) {
        override fun migrate(database: SupportSQLiteDatabase) {
            database.execSQL("ALTER TABLE Contact ADD COLUMN seller_id TEXT NOT NULL DEFAULT ''")
        }
    }

ประการที่สาม

private fun buildDatabase(context: Context) = Room.databaseBuilder(
            context.applicationContext,
            EpayDatabase::class.java,
            "epay"
        )
            .addMigrations(MIGRATION_1_2)
            .build()

สำหรับรายละเอียดเพิ่มเติมโปรดตรวจสอบเอกสารอย่างเป็นทางการ


4

ปัญหานี้เกิดขึ้นส่วนใหญ่ในการพัฒนา

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

ล้างข้อมูลแอปหรือติดตั้งสร้างใหม่หลังจากถอนการติดตั้งก่อนสร้าง

ตอนนี้ฐานข้อมูลเก่าจะไม่ขัดแย้งกับฐานข้อมูลใหม่


หลังจากนั้นก็ยังพัง
user7856586

ข้อยกเว้นคืออะไร? โปรดใส่บันทึกเพื่อ จำกัด ปัญหาให้แคบลง
Extremis II

2
ขอบคุณทุกอย่างเรียบร้อยแล้ว ฉันอ่านandroid:allowBackup="true"และใช้มันอย่างชาญฉลาด
user7856586

1
@ user7856586 แล้ว allowBackup ล่ะ? คุณช่วยสอนเราด้วยสติปัญญาของคุณได้ไหม
Ridcully

@Ridcully คุณสามารถอ่านได้ที่นี่ ทำไมคุณถึงโกรธ?
user7856586

3

ในกรณีของฉันฉันมีคลาส AppDatabase

@Database(entities = {GenreData.class, MoodData.class, SongInfo.class,
    AlbumsInfo.class, UserFolderListsData.class, UserPlaylistResponse.PlayLists.class, InternetConnectionModel.class}, version = 3, exportSchema = false)

ฉันอัปเดตหมายเลขเวอร์ชันนี้และแก้ไขปัญหาได้ ปัญหาเกิดขึ้นเนื่องจากฉันได้เพิ่มคุณสมบัติในคลาส SongInfo และลืมอัปเดตหมายเลขเวอร์ชัน

หวังว่ามันจะช่วยใครบางคน


2

หากคุณกำลังอัปเกรดเวอร์ชัน Room เป็น 1.0.0-alpha9 จากเวอร์ชันเก่าโปรดไปที่บทความด้านล่าง บทความดีมากสำหรับการโยกย้ายจากเวอร์ชันเก่าเป็นเวอร์ชัน 1.0.0-alpha9

https://medium.com/@manuelvicnt/android-room-upgrading-alpha-versions-needs-a-migration-with-kotlin-or-nonnull-7a2d140f05b9

ในห้องเวอร์ชันใหม่ 1.0.0-alpha9 Room เพิ่มการรองรับข้อ จำกัด NOT NULL

ซึ่งจะเปลี่ยนสคีมาที่ห้องสร้างขึ้น เนื่องจากมีการเปลี่ยนแปลง schema จึงยังเปลี่ยน identityHash ของ DB และ Room ใช้เพื่อระบุเวอร์ชัน DB ทุกเวอร์ชันโดยไม่ซ้ำกัน ดังนั้นเราจึงจำเป็นต้องมีการโยกย้าย


2

ในกรณีของฉันฐานข้อมูล ContentProvider และห้องทำงานร่วมกันดังนั้นก่อนอื่นให้ลบการเรียกกลับของ ContentProvider ทั้งหมดบนแอปพลิเคชันที่มีคลาสฐานข้อมูลซึ่งขยาย SqlLiteOpenHelper Class


2

ในกรณีของฉันฉันใช้ธุรกรรมภายในการย้ายข้อมูลและห้องไม่สามารถอัปเดตแฮชโดยใช้ตัวช่วยการย้ายข้อมูล

@get:Rule
val migrationTestHelper: MigrationTestHelper =

MigrationTestHelper(InstrumentationRegistry.getInstrumentation(),
                C2GDatabase::class.java.canonicalName,
                FrameworkSQLiteOpenHelperFactory()) 
/* Testing method throws error*/
db = migrationTestHelper.runMigrationsAndValidate(C2GDatabase.DB_NAME,
            3,
            false,
            C2GDatabase.Migration_1_2(),
            C2GDatabase.Migration_2_3())


override fun migrate(database: SupportSQLiteDatabase) {

/** 
    Error
    database.beginTransaction()
**/
database.execSQL("PRAGMA foreign_keys=off;")
database.execSQL("ALTER TABLE user RENAME TO user_old;")
database.execSQL("CREATE TABLE user ( id_user INTEGER PRIMARY KEY AUTOINCREMENT, external_id INTEGER NOT NULL;")
database.execSQL("INSERT INTO user ( id_user, external_id ) " +
                        " SELECT               id_user, external_id" +  
                        " FROM                 user_old;")

database.execSQL("CREATE UNIQUE INDEX idx_unique_user ON user (external_id);")
database.execSQL("PRAGMA foreign_keys=on;")
database.execSQL("DROP TABLE user_old;")
//database.endTransaction() 
}

ฉันดิ้นรนหลายชั่วโมงและนี่คือทางออก !! ขอบคุณ!!
Javier

1
ในตัวอย่างด้านบนไม่ใช่ธุรกรรมที่เป็นปัญหา คุณลืมตั้งค่าการทำธุรกรรมให้สำเร็จก่อนที่จะสิ้นสุด: <pre> <code> database.beginTransaction () database.setTransactionSuccessful () database.endTransaction () </code> </pre>
birukoff

2
@Database(entities = {Tablename1.class, Tablename2.class}, version = 3, exportSchema = false)

เปลี่ยนหมายเลขเวอร์ชันในคลาส RoomDatabase ของคุณ เพิ่มหมายเลขเวอร์ชัน


2

หากการเพิ่มเวอร์ชันของสคีมาใช้ไม่ได้กับคุณให้ย้ายฐานข้อมูล ในการดำเนินการนี้คุณต้องประกาศการย้ายข้อมูลในตัวสร้างฐานข้อมูล:

Room.databaseBuilder(context, RepoDatabase.class, DB_NAME)
  .addMigrations(FROM_1_TO_2)
.build();

static final Migration FROM_1_TO_2 = new Migration(1, 2) {
@Override
public void migrate(final SupportSQLiteDatabase database) {
    database.execSQL("ALTER TABLE Repo 
                     ADD COLUMN createdAt TEXT");
    }
};

ใช่นี่เป็นวิธีที่เหมาะสม
Bipin Bharti

1

ฉันเพิ่งมีปัญหาคล้ายกันในการทดสอบเอสเพรสโซและสิ่งเดียวที่แก้ไขได้คือการล้างข้อมูลและถอนการติดตั้งแอพทดสอบ androidx เช่น:

adb uninstall androidx.test.orchestrator
adb uninstall androidx.test.services

0

ในกรณีของฉันฉันกำลังอัปเดตฐานข้อมูลที่ฉันจะบรรจุไว้ล่วงหน้ากับแอปของฉัน ข้อเสนอแนะที่นี่ใช้ไม่ได้ผล แต่ในที่สุดฉันก็พบว่าฉันสามารถเปิดไฟล์. db ในโปรแกรมฐานข้อมูลได้ (ฉันใช้ "DB Browser for SQLite") และเปลี่ยน "User version" จาก 2 กลับเป็น 1 ด้วยตนเองหลังจากนั้นก็ทำงานได้อย่างสมบูรณ์

ฉันเดาว่าการอัปเดตใด ๆ ที่คุณทำการเปลี่ยนแปลงผู้ใช้เวอร์ชันนี้และนี่คือสาเหตุที่ฉันได้รับข้อผิดพลาดนี้


คุณสามารถช่วยฉันด้วยเช่นเดียวกัน? ฉันไม่พบเวอร์ชันใน DB Browser สำหรับ SQLite
GreenROBO

ใน tab "Edit pragmas" เรียกว่า "User Version"
Gavin Wright

ใช่. ฉันเข้าใจแล้ว. ขอบคุณสำหรับความช่วยเหลือ Gavin :)
GreenROBO

-1

ในกรณีของฉันฉันลองทำตามทั้งหมดข้างต้นแล้ว ดูเหมือนจะไม่มีอะไรทำงานดังนั้นวิธีแก้ปัญหาสำหรับฉันคือการตั้งค่าandroid:allowBackup="false"ติดตั้งแอปจากนั้นตั้งค่ากลับเป็นจริง

หวังว่าจะช่วยคนอื่น ๆ :)


1
นี่คือสิ่งที่ฉันตอบทำไมต้องตอบซ้ำ?
Divyanshu Negi

-2

ฉันได้รับข้อผิดพลาดเดียวกันในระหว่างโปรแกรมการฝึกอบรมของ Codelabs โดยที่ในเซสชันการฝึกอบรมครั้งหนึ่งฉันได้สร้างโปรเจ็กต์และดำเนินการกับการดำเนินการฐานข้อมูลทั้งหมด ในเซสชันถัดไปฉันกำลังทำงานกับ repo อื่น แต่เป็นส่วนขยายของโครงการก่อนหน้าจากแอปเสริมรุ่นแรกเท่านั้นที่ฉันได้รับข้อผิดพลาด

บางที Studio จะเก็บเทคนิคการตรวจสอบสิทธิ์ด้วยฐานข้อมูลห้องที่ขาดหายไปในโครงสร้างใหม่

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