Есть ли способ достичь такого сценария?
Да, возможно, не идеально, но в принципе: -
- Назовите новую базу данных как-то иначе и скопируйте впапка активов.
- Откройте его с помощью аналогичного помощника, который скопирует его из папки ресурсов, после чего
- продолжит и скопирует строки из соответствующей таблицы и вставит их в соответствующую таблицу предыдущей / старой базы данных.
Возможно, все инициировано с onUpgrade после увеличения номера версии.
Дополнительный комментарий: -
Не могли бы вы показать мне простой пример кода.Я думаю, что копирование данных с использованием курсора - это хороший подход, но я не понимал, как читать таблицы из двух таблиц.
Вот пример выполнения всего этого, включая копирование из ресурсов
Предполагается, что исходная база данных называется events.db и имеет 3 таблицы, а именно: event_table1 (заполнено), event_table2 (также заполнено) и event_table3 empty.
Новая база данных, заполненная event_table3 , называется events_extra.db и помещена в папку ресурсов.
Один класс (не может быть обеспокоен использованием подкласса SQliteOpenHelper) с именем ImportFromSecondaryDB копирует БД из папки активов в качестве второй базы данных, открывает обе, извлекает все строки из вторичной БД (однапросто скопировал из ресурсов) 3-ю таблицу и вставил строки в исходную БД.Наконец, он удаляет все строки из вторичной базы данных.
public class ImportFromSecondaryDB {
public static final int IFSDB_COMPLETIONCODE_ALLREADYDONE = 1;
public static final int IFSDB_COMPLETIONCODE_ERRORCOPYINGDBFROMASSET = 2;
SQLiteDatabase mPrimaryDB;
SQLiteDatabase mSecondaryDB;
int mCompletionCode = 0;
int stage = 0;
ImportFromSecondaryDB(Context context, String primaryDBName, String secondaryDBName) {
File primaryDBFile = new File(context.getDatabasePath(primaryDBName).getPath());
File secondaryDBFile = new File(context.getDatabasePath(secondaryDBName).getPath());
byte[] buffer = new byte[4096];
if (!primaryDBFile.exists()) {
throw new RuntimeException("Unable to Import as the Primary Database does not exist!");
}
if (secondaryDBFile.exists()) {
mCompletionCode = IFSDB_COMPLETIONCODE_ALLREADYDONE;
return;
}
InputStream is;
OutputStream os;
int length = 0;
int copied = 0;
try {
is = context.getAssets().open(secondaryDBName);
stage++;
os = new FileOutputStream(secondaryDBFile);
stage++;
while ((length = is.read(buffer)) > 0) {
copied = copied + length;
os.write(buffer);
}
stage++;
os.flush();
stage++;
os.close();
stage++;
is.close();
stage++;
} catch (IOException e) {
e.printStackTrace();
mCompletionCode = IFSDB_COMPLETIONCODE_ERRORCOPYINGDBFROMASSET;
throw new RuntimeException(
"Error copying secondary database from Asset " + secondaryDBName +
" to " + secondaryDBFile.getPath() + " at stage " + String.valueOf(stage)
);
}
mPrimaryDB = SQLiteDatabase.openDatabase(primaryDBFile.getPath(),null,SQLiteDatabase.OPEN_READWRITE);
mSecondaryDB = SQLiteDatabase.openDatabase(secondaryDBFile.getPath(),null,SQLiteDatabase.OPEN_READWRITE);
ContentValues cv = new ContentValues();
Cursor csr = mSecondaryDB.query("event_table3",null,null,null,null,null,null);
mPrimaryDB.beginTransaction();
while (csr.moveToNext()) {
cv.clear();
cv.put("name",csr.getString(csr.getColumnIndex("name")));
mPrimaryDB.insert("event_table3",null,cv);
}
mPrimaryDB.setTransactionSuccessful();
mPrimaryDB.endTransaction();
mSecondaryDB.delete("event_table3",null,null); //???????
mPrimaryDB.close();
mSecondaryDB.close();
}
public int getCompletionCode() {
return this.mCompletionCode;
}
}
- Примечание. Можно использовать getCompletionCode, чтобы определить, существует ли проблема (уже выполненная), которая не привела к возникновению исключения.
- Обратите внимание, что это не было проверено так много, и он был составлен на скорую руку, поскольку он предназначен только для руководства.
Ниже приведен код, который использовался для вызовавыше из Activity: -
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dumpAllThreeTables(); // Dump Existing tables
ImportFromSecondaryDB mIFSDB = new ImportFromSecondaryDB(this,"events.db","events_extra.db"); // Do the import
dumpAllThreeTables(); // Dump the changed tables
}
private void dumpAllThreeTables() {
SQLiteDatabase mainDB = SQLiteDatabase.openDatabase(this.getDatabasePath("events.db").getPath(),null,SQLiteDatabase.OPEN_READWRITE);
Cursor csr = mainDB.query("event_table1",null,null,null,null,null,null);
DatabaseUtils.dumpCursor(csr);
csr = mainDB.query("event_table2",null,null,null,null,null,null);
DatabaseUtils.dumpCursor(csr);
csr = mainDB.query("event_table3",null,null,null,null,null,null);
DatabaseUtils.dumpCursor(csr);
csr.close();
mainDB.close();
}
}
Первый набор сброшенных таблиц (не end ничего в event_table3): -
12-12 10:43:38.766 2842-2842/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@534c2808
12-12 10:43:38.770 2842-2842/? I/System.out: 0 {
12-12 10:43:38.770 2842-2842/? I/System.out: id=1
12-12 10:43:38.770 2842-2842/? I/System.out: mainname=A
12-12 10:43:38.770 2842-2842/? I/System.out: }
12-12 10:43:38.770 2842-2842/? I/System.out: 1 {
12-12 10:43:38.770 2842-2842/? I/System.out: id=2
12-12 10:43:38.770 2842-2842/? I/System.out: mainname=B
12-12 10:43:38.770 2842-2842/? I/System.out: }
12-12 10:43:38.770 2842-2842/? I/System.out: 2 {
12-12 10:43:38.770 2842-2842/? I/System.out: id=3
12-12 10:43:38.770 2842-2842/? I/System.out: mainname=C
12-12 10:43:38.770 2842-2842/? I/System.out: }
12-12 10:43:38.770 2842-2842/? I/System.out: 3 {
12-12 10:43:38.770 2842-2842/? I/System.out: id=4
12-12 10:43:38.770 2842-2842/? I/System.out: mainname=D
12-12 10:43:38.770 2842-2842/? I/System.out: }
12-12 10:43:38.770 2842-2842/? I/System.out: 4 {
12-12 10:43:38.770 2842-2842/? I/System.out: id=5
12-12 10:43:38.770 2842-2842/? I/System.out: mainname=E
12-12 10:43:38.770 2842-2842/? I/System.out: }
12-12 10:43:38.770 2842-2842/? I/System.out: 5 {
12-12 10:43:38.770 2842-2842/? I/System.out: id=6
12-12 10:43:38.770 2842-2842/? I/System.out: mainname=F
12-12 10:43:38.770 2842-2842/? I/System.out: }
12-12 10:43:38.770 2842-2842/? I/System.out: 6 {
12-12 10:43:38.770 2842-2842/? I/System.out: id=7
12-12 10:43:38.770 2842-2842/? I/System.out: mainname=G
12-12 10:43:38.770 2842-2842/? I/System.out: }
12-12 10:43:38.770 2842-2842/? I/System.out: 7 {
12-12 10:43:38.770 2842-2842/? I/System.out: id=8
12-12 10:43:38.770 2842-2842/? I/System.out: mainname=H
12-12 10:43:38.770 2842-2842/? I/System.out: }
12-12 10:43:38.770 2842-2842/? I/System.out: 8 {
12-12 10:43:38.770 2842-2842/? I/System.out: id=9
12-12 10:43:38.770 2842-2842/? I/System.out: mainname=I
12-12 10:43:38.770 2842-2842/? I/System.out: }
12-12 10:43:38.770 2842-2842/? I/System.out: <<<<<
12-12 10:43:38.770 2842-2842/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@534af7a8
12-12 10:43:38.770 2842-2842/? I/System.out: 0 {
12-12 10:43:38.770 2842-2842/? I/System.out: id=1
12-12 10:43:38.770 2842-2842/? I/System.out: secondaryname=Horse
12-12 10:43:38.770 2842-2842/? I/System.out: }
12-12 10:43:38.770 2842-2842/? I/System.out: 1 {
12-12 10:43:38.770 2842-2842/? I/System.out: id=2
12-12 10:43:38.770 2842-2842/? I/System.out: secondaryname=Cow
12-12 10:43:38.770 2842-2842/? I/System.out: }
12-12 10:43:38.770 2842-2842/? I/System.out: 2 {
12-12 10:43:38.770 2842-2842/? I/System.out: id=3
12-12 10:43:38.774 2842-2842/? I/System.out: secondaryname=Rabbit
12-12 10:43:38.774 2842-2842/? I/System.out: }
12-12 10:43:38.774 2842-2842/? I/System.out: 3 {
12-12 10:43:38.774 2842-2842/? I/System.out: id=4
12-12 10:43:38.774 2842-2842/? I/System.out: secondaryname=Hare
12-12 10:43:38.774 2842-2842/? I/System.out: }
12-12 10:43:38.774 2842-2842/? I/System.out: 4 {
12-12 10:43:38.774 2842-2842/? I/System.out: id=5
12-12 10:43:38.774 2842-2842/? I/System.out: secondaryname=Cat
12-12 10:43:38.774 2842-2842/? I/System.out: }
12-12 10:43:38.774 2842-2842/? I/System.out: 5 {
12-12 10:43:38.774 2842-2842/? I/System.out: id=6
12-12 10:43:38.774 2842-2842/? I/System.out: secondaryname=Dog
12-12 10:43:38.774 2842-2842/? I/System.out: }
12-12 10:43:38.774 2842-2842/? I/System.out: 6 {
12-12 10:43:38.774 2842-2842/? I/System.out: id=7
12-12 10:43:38.774 2842-2842/? I/System.out: secondaryname=Porcupine
12-12 10:43:38.774 2842-2842/? I/System.out: }
12-12 10:43:38.774 2842-2842/? I/System.out: 7 {
12-12 10:43:38.774 2842-2842/? I/System.out: id=8
12-12 10:43:38.774 2842-2842/? I/System.out: secondaryname=Elephant
12-12 10:43:38.774 2842-2842/? I/System.out: }
12-12 10:43:38.774 2842-2842/? I/System.out: 8 {
12-12 10:43:38.774 2842-2842/? I/System.out: id=9
12-12 10:43:38.774 2842-2842/? I/System.out: secondaryname=Sheep
12-12 10:43:38.774 2842-2842/? I/System.out: }
12-12 10:43:38.774 2842-2842/? I/System.out: 9 {
12-12 10:43:38.774 2842-2842/? I/System.out: id=10
12-12 10:43:38.774 2842-2842/? I/System.out: secondaryname=Goat
12-12 10:43:38.774 2842-2842/? I/System.out: }
12-12 10:43:38.774 2842-2842/? I/System.out: <<<<<
12-12 10:43:38.774 2842-2842/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@534c6e1c
12-12 10:43:38.774 2842-2842/? I/System.out: <<<<<
Второй набор сброшенных таблиц (посмотрите, как event_table3(последний дамп) теперь содержит данные): -
12-12 10:43:38.790 2842-2842/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@534ae284
12-12 10:43:38.790 2842-2842/? I/System.out: 0 {
12-12 10:43:38.790 2842-2842/? I/System.out: id=1
12-12 10:43:38.790 2842-2842/? I/System.out: mainname=A
12-12 10:43:38.790 2842-2842/? I/System.out: }
12-12 10:43:38.790 2842-2842/? I/System.out: 1 {
12-12 10:43:38.790 2842-2842/? I/System.out: id=2
12-12 10:43:38.790 2842-2842/? I/System.out: mainname=B
12-12 10:43:38.790 2842-2842/? I/System.out: }
12-12 10:43:38.790 2842-2842/? I/System.out: 2 {
12-12 10:43:38.790 2842-2842/? I/System.out: id=3
12-12 10:43:38.790 2842-2842/? I/System.out: mainname=C
12-12 10:43:38.790 2842-2842/? I/System.out: }
12-12 10:43:38.790 2842-2842/? I/System.out: 3 {
12-12 10:43:38.790 2842-2842/? I/System.out: id=4
12-12 10:43:38.790 2842-2842/? I/System.out: mainname=D
12-12 10:43:38.790 2842-2842/? I/System.out: }
12-12 10:43:38.790 2842-2842/? I/System.out: 4 {
12-12 10:43:38.790 2842-2842/? I/System.out: id=5
12-12 10:43:38.790 2842-2842/? I/System.out: mainname=E
12-12 10:43:38.790 2842-2842/? I/System.out: }
12-12 10:43:38.790 2842-2842/? I/System.out: 5 {
12-12 10:43:38.790 2842-2842/? I/System.out: id=6
12-12 10:43:38.790 2842-2842/? I/System.out: mainname=F
12-12 10:43:38.790 2842-2842/? I/System.out: }
12-12 10:43:38.790 2842-2842/? I/System.out: 6 {
12-12 10:43:38.790 2842-2842/? I/System.out: id=7
12-12 10:43:38.790 2842-2842/? I/System.out: mainname=G
12-12 10:43:38.790 2842-2842/? I/System.out: }
12-12 10:43:38.790 2842-2842/? I/System.out: 7 {
12-12 10:43:38.790 2842-2842/? I/System.out: id=8
12-12 10:43:38.790 2842-2842/? I/System.out: mainname=H
12-12 10:43:38.790 2842-2842/? I/System.out: }
12-12 10:43:38.790 2842-2842/? I/System.out: 8 {
12-12 10:43:38.790 2842-2842/? I/System.out: id=9
12-12 10:43:38.790 2842-2842/? I/System.out: mainname=I
12-12 10:43:38.790 2842-2842/? I/System.out: }
12-12 10:43:38.790 2842-2842/? I/System.out: <<<<<
12-12 10:43:38.790 2842-2842/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@534c44b4
12-12 10:43:38.794 2842-2842/? I/System.out: 0 {
12-12 10:43:38.794 2842-2842/? I/System.out: id=1
12-12 10:43:38.794 2842-2842/? I/System.out: secondaryname=Horse
12-12 10:43:38.794 2842-2842/? I/System.out: }
12-12 10:43:38.794 2842-2842/? I/System.out: 1 {
12-12 10:43:38.794 2842-2842/? I/System.out: id=2
12-12 10:43:38.794 2842-2842/? I/System.out: secondaryname=Cow
12-12 10:43:38.794 2842-2842/? I/System.out: }
12-12 10:43:38.794 2842-2842/? I/System.out: 2 {
12-12 10:43:38.794 2842-2842/? I/System.out: id=3
12-12 10:43:38.794 2842-2842/? I/System.out: secondaryname=Rabbit
12-12 10:43:38.794 2842-2842/? I/System.out: }
12-12 10:43:38.794 2842-2842/? I/System.out: 3 {
12-12 10:43:38.794 2842-2842/? I/System.out: id=4
12-12 10:43:38.794 2842-2842/? I/System.out: secondaryname=Hare
12-12 10:43:38.794 2842-2842/? I/System.out: }
12-12 10:43:38.794 2842-2842/? I/System.out: 4 {
12-12 10:43:38.794 2842-2842/? I/System.out: id=5
12-12 10:43:38.794 2842-2842/? I/System.out: secondaryname=Cat
12-12 10:43:38.794 2842-2842/? I/System.out: }
12-12 10:43:38.794 2842-2842/? I/System.out: 5 {
12-12 10:43:38.794 2842-2842/? I/System.out: id=6
12-12 10:43:38.794 2842-2842/? I/System.out: secondaryname=Dog
12-12 10:43:38.794 2842-2842/? I/System.out: }
12-12 10:43:38.794 2842-2842/? I/System.out: 6 {
12-12 10:43:38.794 2842-2842/? I/System.out: id=7
12-12 10:43:38.798 2842-2842/? I/System.out: secondaryname=Porcupine
12-12 10:43:38.798 2842-2842/? I/System.out: }
12-12 10:43:38.798 2842-2842/? I/System.out: 7 {
12-12 10:43:38.798 2842-2842/? I/System.out: id=8
12-12 10:43:38.802 2842-2842/? I/System.out: secondaryname=Elephant
12-12 10:43:38.802 2842-2842/? I/System.out: }
12-12 10:43:38.802 2842-2842/? I/System.out: 8 {
12-12 10:43:38.802 2842-2842/? I/System.out: id=9
12-12 10:43:38.802 2842-2842/? I/System.out: secondaryname=Sheep
12-12 10:43:38.802 2842-2842/? I/System.out: }
12-12 10:43:38.802 2842-2842/? I/System.out: 9 {
12-12 10:43:38.802 2842-2842/? I/System.out: id=10
12-12 10:43:38.802 2842-2842/? I/System.out: secondaryname=Goat
12-12 10:43:38.802 2842-2842/? I/System.out: }
12-12 10:43:38.802 2842-2842/? I/System.out: <<<<<
12-12 10:43:38.802 2842-2842/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@534c48c4
12-12 10:43:38.802 2842-2842/? I/System.out: 0 {
12-12 10:43:38.802 2842-2842/? I/System.out: id=1
12-12 10:43:38.802 2842-2842/? I/System.out: name=Z
12-12 10:43:38.802 2842-2842/? I/System.out: }
12-12 10:43:38.802 2842-2842/? I/System.out: 1 {
12-12 10:43:38.802 2842-2842/? I/System.out: id=2
12-12 10:43:38.802 2842-2842/? I/System.out: name=X
12-12 10:43:38.802 2842-2842/? I/System.out: }
12-12 10:43:38.802 2842-2842/? I/System.out: 2 {
12-12 10:43:38.802 2842-2842/? I/System.out: id=3
12-12 10:43:38.802 2842-2842/? I/System.out: name=Y
12-12 10:43:38.802 2842-2842/? I/System.out: }
12-12 10:43:38.802 2842-2842/? I/System.out: 3 {
12-12 10:43:38.802 2842-2842/? I/System.out: id=4
12-12 10:43:38.802 2842-2842/? I/System.out: name=W
12-12 10:43:38.802 2842-2842/? I/System.out: }
12-12 10:43:38.802 2842-2842/? I/System.out: 4 {
12-12 10:43:38.802 2842-2842/? I/System.out: id=5
12-12 10:43:38.802 2842-2842/? I/System.out: name=U
12-12 10:43:38.802 2842-2842/? I/System.out: }
12-12 10:43:38.802 2842-2842/? I/System.out: 5 {
12-12 10:43:38.802 2842-2842/? I/System.out: id=6
12-12 10:43:38.802 2842-2842/? I/System.out: name=R
12-12 10:43:38.802 2842-2842/? I/System.out: }
12-12 10:43:38.802 2842-2842/? I/System.out: 6 {
12-12 10:43:38.802 2842-2842/? I/System.out: id=7
12-12 10:43:38.802 2842-2842/? I/System.out: name=S
12-12 10:43:38.802 2842-2842/? I/System.out: }
12-12 10:43:38.802 2842-2842/? I/System.out: 7 {
12-12 10:43:38.802 2842-2842/? I/System.out: id=8
12-12 10:43:38.802 2842-2842/? I/System.out: name=T
12-12 10:43:38.802 2842-2842/? I/System.out: }
12-12 10:43:38.802 2842-2842/? I/System.out: <<<<<
Дополнительно 2 - Включение в onUpgrade
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String DB_PATH = "/data/data/com.calendar.shanu.calendar/databases/";
private static final String DB_NAME = "events.db"; //<<<<<<<<<<< Changed for testing
private static final int DB_VERSION = 2; //<<<<<<<<<< Changed for Testing
private final Context myContext;
public SQLiteDatabase db;
public DatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
this.myContext = context;
}
public void createDataBase() throws IOException {
boolean dbExist = checkDataBase();
if (dbExist) {
this.getWritableDatabase();
} else {
this.getWritableDatabase();
try {
this.close();
copyDataBase();
} catch (IOException e) {
throw new Error("Error copying database");
}
}
}
private boolean checkDataBase() {
SQLiteDatabase checkDB = null;
try {
String myPath = DB_PATH + DB_NAME;
checkDB = SQLiteDatabase.openDatabase(myPath, null,SQLiteDatabase.OPEN_READWRITE);
//checkDB.setVersion(DB_VERSION);
} catch (SQLiteException e) {
}
if (checkDB != null)
checkDB.close();
return checkDB != null ? true : false;
}
private void copyDataBase() throws IOException {
InputStream myInput = myContext.getAssets().open(DB_NAME);
String outFileName = DB_PATH + DB_NAME;
OutputStream myOutput = new FileOutputStream(outFileName);
byte[] buffer = new byte[2048];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
//myDataBase.setVersion(DATABASE_VERSION);
}
public void opendb() throws SQLException {
String myPath = DB_PATH + DB_NAME;
db = SQLiteDatabase.openDatabase(myPath, null,SQLiteDatabase.OPEN_READWRITE);
Log.d("Test", "Database version: " +db.getVersion());
}
@Override
public synchronized void close() {
if (db != null)
db.close();
super.close();
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if(newVersion > oldVersion){
importFromSecondaryDB(myContext,db,"events_extra.db"); //<<<<<<<<<<
}
}
public void closedb(){
if (db!=null){
db.close();
}
}
private int importFromSecondaryDB(Context context, SQLiteDatabase maindb, String secondaryDBName) {
File primaryDBFile = new File(maindb.getPath());
File secondaryDBFile = new File(context.getDatabasePath(secondaryDBName).getPath());
byte[] buffer = new byte[4096];
// Check that the main database exist, if not then throw a runtime exception
if (!primaryDBFile.exists()) {
throw new RuntimeException("Unable to Import as the Primary Database does not exist!");
}
// If the secondary database exists then it has already been copied and thus data has been loaded
// so return (can check returned code for allready done)
if (secondaryDBFile.exists()) {
return 1;
}
//Prepare for file handling (copy)
InputStream is;
OutputStream os;
int length;
int copied = 0;
try {
is = context.getAssets().open(secondaryDBName); // Get the assets file
os = new FileOutputStream(secondaryDBFile); // Get the file to be written to
// Loop though the asset file in chunks reading it and then writing to output
while ((length = is.read(buffer)) > 0) {
copied = copied + length;
os.write(buffer);
}
// Copy done so flush and close files
os.flush();
os.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(
"Error copying secondary database from Asset " + secondaryDBName +
" to " + secondaryDBFile.getPath()
);
}
// Open the newly copied database
SQLiteDatabase mSecondaryDB = SQLiteDatabase.openDatabase(secondaryDBFile.getPath(),null,SQLiteDatabase.OPEN_READWRITE);
//Copy the rows from the secondary (new) database, from table event_table3 to the main database's event_table3
//<<<<<<<<<< Note will have to be tailored to suit. >>>>>>>>>>>
ContentValues cv = new ContentValues();
// Extract the tables
Cursor csr = mSecondaryDB.query("event_table3",null,null,null,null,null,null);
// Do in a Transaction
maindb.beginTransaction();
// Loop through extracted rows
while (csr.moveToNext()) {
cv.clear();
cv.put("name",csr.getString(csr.getColumnIndex("name")));
maindb.insert("event_table3",null,cv);
}
// ALl done so commit and close the transaction
maindb.setTransactionSuccessful();
maindb.endTransaction();
// OPTIONAL delete the rows from the secondary table as they have been applied
mSecondaryDB.delete("event_table3",null,null); //???????
// Finally close the secondary database as done with it (main stays open)
mSecondaryDB.close();
return 0;
}
}