Вы повторно копируете файл ресурсов и удаляете приложение каждый раз, когда вносите изменения? Если нет, и это не решает проблему, то: -
Если вы компилируете код комнаты, посмотрите на java (сгенерированный) в your_database_class _impl (где your_database_class - это ваша @ База данных имя класса) и по методу createAllTables . Это SQL используется для создания базы данных (вы можете игнорировать room_master SQL).
Например (это основано на вашей сущности и минимальных ссылочных таблицах): -
@Override
public void createAllTables(SupportSQLiteDatabase _db) {
_db.execSQL("CREATE TABLE IF NOT EXISTS `Authors` (`AuthorID` INTEGER, `AuthorName` TEXT, PRIMARY KEY(`AuthorID`))");
_db.execSQL("CREATE TABLE IF NOT EXISTS `Sources` (`SourceID` INTEGER, `SourceName` TEXT, PRIMARY KEY(`SourceID`))");
_db.execSQL("CREATE TABLE IF NOT EXISTS `Author_By_Source` (`AuthorID` INTEGER NOT NULL, `SourceID` INTEGER NOT NULL, PRIMARY KEY(`AuthorID`, `SourceID`), FOREIGN KEY(`AuthorID`) REFERENCES `Authors`(`AuthorID`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`SourceID`) REFERENCES `Sources`(`SourceID`) ON UPDATE NO ACTION ON DELETE NO ACTION )");
_db.execSQL("CREATE INDEX IF NOT EXISTS `index_Author_By_Source_AuthorID` ON `Author_By_Source` (`AuthorID`)");
_db.execSQL("CREATE INDEX IF NOT EXISTS `index_Author_By_Source_SourceID` ON `Author_By_Source` (`SourceID`)");
_db.execSQL("CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)");
_db.execSQL("INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '953f8512db886fb7d206fa561a7117c4')");
}
Вам необходимо соответствующим образом преобразовать базу данных, то есть в соответствии с определением, например, Вы могли бы для вышеперечисленного в SQLite Studio использовать
/* Just once */
PRAGMA foreign_keys = 0;
/* Per table */
DROP TABLE IF EXISTS Author_By_Source_new;
DROP TABLE IF EXISTS Author_By_Source_original;
CREATE TABLE IF NOT EXISTS Author_By_Source_new copy_generated_sql_for_the_column_definitions_etc;
DELETE FROM Author_By_Source_new;
INSERT INTO Author_By_Source_new SELECT * FROM Author_By_Source;
ALTER TABLE Author_By_Source RENAME TO Author_By_Source_original;
ALTER TABLE Author_By_Source_new RENAME TO Author_By_Source;
/* IF HAPPY THEN DO */
-- DROP TABLE IF EXISTS Author_By_Source_original; /* NOTE TURNED OFF */
...... do the equivalent for all tables
/* Just once */
PRAGMA foreign_keys = 1;
PRAGMA foreign_key_check;
PRAGMA integrity_check;
Пример
Вот пример, основанный на том, что доступны из вашего кода.
Исходная предварительно заполненная база данных
База данных была создана с помощью средства управления SQLite (Navicat) с использованием: -
DROP TABLE IF EXISTS Author_By_Source;
DROP TABLE IF EXISTS Authors;
DROP TABLE IF EXISTS Sources;
CREATE TABLE IF NOT EXISTS Authors (AuthorID INTEGER PRIMARY KEY, AuthorName TEXT);
CREATE TABLE IF NOT EXISTS Sources (SourceID INTEGER PRIMARY KEY, SourceName TEXT);
/* Create the table so that it would cause issues in Room */
CREATE TABLE IF NOT EXISTS Author_By_Source (
AuthorId INTEGER, SourceId INTEGER,
FOREIGN KEY (AuthorID) REFERENCES Authors(AuthorID),
FOREIGN KEY (SourceID) REFERENCES Sources(SourceID)
);
INSERT INTO Authors (AuthorName) VALUES ('Fred'),('Mary'),('Joan'),('Bert'),('Alan');
INSERT INTO Sources (SourceName) VALUES ('S1'),('S2'),('S3'),('S4'),('S5');
INSERT INTO Author_By_Source VALUES(1,1),(2,2),(3,3),(4,4),(5,5),(1,4),(3,4),(5,2);
SELECT AuthorName, SourceName
FROM Author_By_Source
JOIN Authors ON Author_By_Source.AuthorID = Authors.AuthorID
JOIN Sources ON Author_By_Source.SourceID = Sources.SourceID
;
После запуска Существо: -
AuthorName SourceName
Fred S1
Mary S2
Joan S3
Bert S4
Alan S5
Fred S4
Joan S4
Alan S2
Как и ожидалось, попытка использовать это приводит к: -
java.lang.RuntimeException: Unable to start activity ComponentInfo{a.a.so59756782javaroomprepopulatedconversion/a.a.so59756782javaroomprepopulatedconversion.MainActivity}: java.lang.IllegalStateException: Pre-packaged database has an invalid schema: Authors(a.a.so59756782javaroomprepopulatedconversion.Authors).
Expected:
TableInfo{name='Authors', columns={AuthorName=Column{name='AuthorName', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, AuthorID=Column{name='AuthorID', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='null'}}, foreignKeys=[], indices=[]}
Found:
TableInfo{name='Authors', columns={AuthorID=Column{name='AuthorID', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'}, AuthorName=Column{name='AuthorName', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
Преобразованию
Следующее, основанное на ответе, использовалось для преобразования база данных: -
BEGIN TRANSACTION;
DROP TABLE IF EXISTS Author_By_Source;
DROP TABLE IF EXISTS Authors;
DROP TABLE IF EXISTS Sources;
CREATE TABLE IF NOT EXISTS `Authors` (`AuthorID` INTEGER NOT NULL, `AuthorName` TEXT, PRIMARY KEY(`AuthorID`));
CREATE TABLE IF NOT EXISTS `Sources` (`SourceID` INTEGER NOT NULL, `SourceName` TEXT, PRIMARY KEY(`SourceID`));
/* Create the table so that it would cause issues in Room */
CREATE TABLE IF NOT EXISTS Author_By_Source (
AuthorId INTEGER, SourceId INTEGER,
FOREIGN KEY (AuthorID) REFERENCES Authors(AuthorID),
FOREIGN KEY (SourceID) REFERENCES Sources(SourceID)
);
INSERT INTO Authors (AuthorName) VALUES ('Fred'),('Mary'),('Joan'),('Bert'),('Alan');
INSERT INTO Sources (SourceName) VALUES ('S1'),('S2'),('S3'),('S4'),('S5');
INSERT INTO Author_By_Source VALUES(1,1),(2,2),(3,3),(4,4),(5,5),(1,4),(3,4),(5,2);
SELECT AuthorName, SourceName
FROM Author_By_Source
JOIN Authors ON Author_By_Source.AuthorID = Authors.AuthorID
JOIN Sources ON Author_By_Source.SourceID = Sources.SourceID
;
/* Just once */
PRAGMA foreign_keys = 0;
/* Per table */
DROP TABLE IF EXISTS Author_By_Source_new;
DROP TABLE IF EXISTS Author_By_Source_original;
CREATE TABLE IF NOT EXISTS `Author_By_Source_new`
(
`AuthorID` INTEGER NOT NULL,
`SourceID` INTEGER NOT NULL,
PRIMARY KEY(`AuthorID`, `SourceID`),
FOREIGN KEY(`AuthorID`) REFERENCES `Authors`(`AuthorID`) ON UPDATE NO ACTION ON DELETE NO ACTION ,
FOREIGN KEY(`SourceID`) REFERENCES `Sources`(`SourceID`) ON UPDATE NO ACTION ON DELETE NO ACTION
);
DELETE FROM Author_By_Source_new;
INSERT INTO Author_By_Source_new SELECT * FROM Author_By_Source;
ALTER TABLE Author_By_Source RENAME TO Author_By_Source_original;
ALTER TABLE Author_By_Source_new RENAME TO Author_By_Source;
/* IF HAPPY THEN DO */
DROP TABLE IF EXISTS Author_By_Source_original;
-- ...... do the equivalent for all tables
CREATE INDEX IF NOT EXISTS `index_Author_By_Source_SourceID` ON `Author_By_Source` (`SourceID`);
CREATE INDEX IF NOT EXISTS `index_Author_By_Source_AuthorID` ON `Author_By_Source` (`AuthorID`);
COMMIT;
/* Just once */
PRAGMA foreign_keys = 1;
PRAGMA foreign_key_check;
PRAGMA integrity_check;
SELECT sql FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite%';
SELECT AuthorName, SourceName
FROM Author_By_Source
JOIN Authors ON Author_By_Source.AuthorID = Authors.AuthorID
JOIN Sources ON Author_By_Source.SourceID = Sources.SourceID
;
База данных была закрыта, отметки времени и размера проверены, а затем файл базы данных заменил существующий файл в папке ресурсов. Приложение было удалено, а затем повторно выполнено в MainActivity: используется для удобства.
myDB.getOpenHelper().getWritableDatabase();
используется для принудительного немедленного открытия и, следовательно, копирования базы данных.
getAllAuthorsWithSources()
делает это так говорит, используя
@Query("SELECT * FROM Author_By_Source")
List<AuthorWithSources> getAllAuthorsWithSources();
AuthorWithSources будучи: -
public class AuthorWithSources {
@Embedded
AuthorBySource authorBySource;
@Relation(entity = Authors.class,parentColumn = "AuthorID",entityColumn = "AuthorID")
Authors authors;
@Relation(entity = Sources.class,parentColumn = "SourceID",entityColumn = "SourceID")
Sources sources;
}
Результат
Нет ошибок и в журнале: -
2020-01-16 10:09:23.623 D/AUTHORSOURCEINFO: Author = FredSource = S1
2020-01-16 10:09:23.623 D/AUTHORSOURCEINFO: Author = MarySource = S2
2020-01-16 10:09:23.623 D/AUTHORSOURCEINFO: Author = JoanSource = S3
2020-01-16 10:09:23.623 D/AUTHORSOURCEINFO: Author = BertSource = S4
2020-01-16 10:09:23.623 D/AUTHORSOURCEINFO: Author = AlanSource = S5
2020-01-16 10:09:23.623 D/AUTHORSOURCEINFO: Author = FredSource = S4
2020-01-16 10:09:23.623 D/AUTHORSOURCEINFO: Author = JoanSource = S4
2020-01-16 10:09:23.623 D/AUTHORSOURCEINFO: Author = AlanSource = S2
Альтернативный подход
Существует инструмент, как приложение, который преобразует базы данных для использования в Room и генерирует код java для сущностей / Dao's.
Инструмент подробно здесь RoomExistingSQLiteDBConverter
Использование инструмента и
- копирование сгенерированного java исходного кода в проект а затем
- посещение каждого файла для разрешения импорта (предполагается, что правильное имя пакета было введите в противном случае пакет также должен быть скорректирован или добавлен) и затем
- создание папки ресурсов в проекте и затем
- копирование сгенерированной базы данных
и, наконец, создание кода для использования базы данных, например
soanswersDatabase = Room.databaseBuilder(this,SoanswersDatabase.class,SoanswersDatabase.DBNAME)
.allowMainThreadQueries()
.createFromAsset(SoanswersDatabase.DBNAME)
.build();
List<Author_By_Source> authorBySourceList = soanswersDatabase.getAuthor_By_SourceDao().getEveryAuthor_By_Source();
for (Author_By_Source abs: authorBySourceList) {
Log.d("AUTHORSOURCEINFO",
"AuthorReference = " + String.valueOf(abs.getAuthorId())
+ " Sourcereference = " + String.valueOf(abs.getSourceId())
);
}
- , т. Е. Приведенный выше код является единственным введенным кодом. Результат: -
2020-01-16 10:46:27.907 D/AUTHORSOURCEINFO: AuthorReference = 1 Sourcereference = 1
2020-01-16 10:46:27.907 D/AUTHORSOURCEINFO: AuthorReference = 2 Sourcereference = 2
2020-01-16 10:46:27.907 D/AUTHORSOURCEINFO: AuthorReference = 3 Sourcereference = 3
2020-01-16 10:46:27.907 D/AUTHORSOURCEINFO: AuthorReference = 4 Sourcereference = 4
2020-01-16 10:46:27.907 D/AUTHORSOURCEINFO: AuthorReference = 5 Sourcereference = 5
2020-01-16 10:46:27.907 D/AUTHORSOURCEINFO: AuthorReference = 1 Sourcereference = 4
2020-01-16 10:46:27.907 D/AUTHORSOURCEINFO: AuthorReference = 3 Sourcereference = 4
2020-01-16 10:46:27.907 D/AUTHORSOURCEINFO: AuthorReference = 5 Sourcereference = 2