greenrobot / greenDAO

greenDAO is a light & fast ORM solution for Android that maps objects to SQLite databases.
http://greenrobot.org/greendao/
12.63k stars 2.89k forks source link

No such column. Possible migration fail with multiple databases & schemas #1064

Closed songliao-branch closed 3 years ago

songliao-branch commented 3 years ago

I am running into some weird bugs with migration. So far I cannot reproduce this issue. I have checked all the OpenHelpers including getWritableDatabase are called in the same handler thread. So threading-issue is unlikely.

In the upgrade, we simply added two string properties to the table UserRecord...

My app has multiple modules, one greendao module for nearly all entites and one login module for login-related entities. Each has a separate database and schema versions. in project's build.grade

  dependencies {
        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'

in login module's build.gradle

apply plugin: 'org.greenrobot.greendao'
greendao {
    schemaVersion 90
    daoPackage 'com.mypackage.login.entity'
}

and in greendao module's build.gradle

apply plugin: 'org.greenrobot.greendao'
greendao {
    schemaVersion 90
    daoPackage 'com.mypackage.greendao.entity'
}

As you can see. There are two schemas.. I read some closed issues multiple databases and schema is not supported directly using the gradle plugin..https://github.com/greenrobot/greenDAO/issues/676 Could this multiple schema-thing be the issue?

Currently greendao version is on 3.2.2 as well as greendao-generator

Fatal Exception: android.database.sqlite.SQLiteException: no such column: T.COLORFUL_NICK_NAME (code 1 SQLITE_ERROR[1]): , while compiling: SELECT T."_id",T."USER_ID",T."NICK_NAME",T."ACCOUNT",T."PASSWORD",T."USER_ICON",T."LOGIN_TYPE",T."LOGIN_TIME",T."HAS_PASSWORD",T."COLORFUL_NICK_NAME",T."AVATAR_FRAME" FROM "USER_RECORD" T  WHERE T."USER_ID"=?
       at android.database.sqlite.SQLiteConnection.nativePrepareStatement(SQLiteConnection.java)
       at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:1372)
       at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:811)
       at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:590)
       at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:62)
       at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
       at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:46)
       at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1959)
       at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1898)
       at org.greenrobot.greendao.b.f.a(StandardDatabase.java:1)
       at org.greenrobot.greendao.d.h.c(Query.java:2)
       at org.greenrobot.greendao.d.i.c(QueryBuilder.java:1)
       at com.***.login.d.m.c(UserRecordHelper.java:4)
       at com.***.login.d.m.a(UserRecordHelper.java:13)
       at com.***.login.d.c.run(:4)
       at android.os.Handler.handleCallback(Handler.java:883)
       at android.os.Handler.dispatchMessage(Handler.java:100)
       at android.os.Looper.loop(Looper.java:237)
       at android.os.HandlerThread.run(HandlerThread.java:67)

Below is the opener. io.github.yuweiguocn:GreenDaoUpgradeHelper:v2.2.1 is used here.. In login module, the opener is below

public class DBOpenHelper extends  DaoMaster.DevOpenHelper{
    public DBOpenHelper(Context context, String name) {
        super(context, name);
    }
    @Override
    public void onUpgrade(Database db, int oldVersion, int newVersion) {
        MigrationHelper.migrate(db,new MigrationHelper.ReCreateAllTableListener(){

            @Override
            public void onCreateAllTables(Database db, boolean ifNotExists) {
                DaoMaster.createAllTables(db, ifNotExists);
            }

            @Override
            public void onDropAllTables(Database db, boolean ifExists) {
                DaoMaster.dropAllTables(db, ifExists);
            }
        }, UserRecordDao.class);
    }
}

in greendao module, the opener is below:

public class DBOpenHelper extends DaoMaster.DevOpenHelper {

    public DBOpenHelper(Context context, String name) {
        super(context, name);
    }

    @Override
    public void onUpgrade(Database db, int oldVersion, int newVersion) {
        MigrationHelper.migrate(db, new MigrationHelper.ReCreateAllTableListener() {

                    @Override
                    public void onCreateAllTables(Database db, boolean ifNotExists) {
                        DaoMaster.createAllTables(db, ifNotExists);
                    }
                    @Override
                    public void onDropAllTables(Database db, boolean ifExists) {
                        DaoMaster.dropAllTables(db, ifExists);
                    }
                }, GameDao.class, VideoInfoDao.class, FriendDao.class
                TeamUIMessageDao.class, PartyMemberInfoDao.class, TribeMemberDao.class,
                UserCacheDao.class, VideoDetailInfoDao.class);
    }
}
songliao-branch commented 3 years ago

Oops. my bad. I'm using it all wrong. I have multiple databases and one happened to migrate in a separate thread, causing a racing condition for MigrationHelper.