greendao3.0版本更新 新增字段遇到的問(wèn)題

問(wèn)題描述

前段時(shí)間在公司有項(xiàng)目需要更新版本吠卷。在新增的功能需求里王悍,需要對(duì)greendao里的Entity實(shí)體類(lèi)新增一個(gè)字段当船。

最開(kāi)始覺(jué)得只需要新增一個(gè)對(duì)象后题画,在gradle中修改greendao版本號(hào)之后重新build項(xiàng)目即可。


@Entity

public class BibleInspirationDB implements Serializable {

    static final long serialVersionUID = -15515456L;

    @Id(autoincrement = true)

    private Long _id;

    private String bibleId;                //書(shū)籍ID

    private String bookName;                //書(shū)名

    private String InspirationContent;      //靈感的文本

    private String rollTitle;

    private String rollIndex;              //第幾卷

    private String secIndex;                //第幾章

    private String partIndex;              //第幾節(jié)  節(jié)可以保存多個(gè)德频,用,隔開(kāi)

    private long saveTime;                 

    private String content;               

    private String netId;   



    private String testId;                  //---->需要新增的字段

    @Transient      //:添加此標(biāo)記后不會(huì)生成數(shù)據(jù)庫(kù)表的列

    private boolean isSelected;



    ......

升級(jí)greendao版本


greendao {

    //指定數(shù)據(jù)庫(kù)schema版本號(hào)苍息,遷移等操作會(huì)用到 

    schemaVersion 16  // 將上一版本的15修改為16

}

但是在重新運(yùn)行項(xiàng)目后報(bào)錯(cuò)提示沒(méi)有辦法找到新增字段。

原因:

后進(jìn)過(guò)多次排查 發(fā)現(xiàn)是在配置greendao版本的時(shí)候,將其寫(xiě)在了


android{

    ....

    greendao {

        //指定數(shù)據(jù)庫(kù)schema版本號(hào)竞思,遷移等操作會(huì)用到 

        schemaVersion 16  // 將上一版本的15修改為16

    }

}

導(dǎo)致更改版本號(hào)之后無(wú)法識(shí)別

補(bǔ)充:

當(dāng)發(fā)現(xiàn)一些有違正潮硪辏現(xiàn)象的問(wèn)題時(shí),且在網(wǎng)上無(wú)法相同現(xiàn)象的情況盖喷,大多數(shù)原因是因?yàn)殚_(kāi)發(fā)過(guò)程中一些基礎(chǔ)的配置出現(xiàn)問(wèn)題引起爆办。當(dāng)往往因?yàn)榻?jīng)常配置該設(shè)置,所以出現(xiàn)問(wèn)題的同時(shí)不會(huì)意識(shí)到是最初的原因引起的课梳。這一點(diǎn)望自己在今后開(kāi)發(fā)過(guò)程中牢記距辆。

此次學(xué)習(xí)到的一些額外知識(shí)

這次在網(wǎng)上尋找問(wèn)題時(shí),發(fā)現(xiàn)有其他博主提到暮刃,在greendao新增字段更新后挑格,會(huì)出現(xiàn)原有的舊數(shù)據(jù)被清除的情況。他們的建議方案是在初始化數(shù)據(jù)庫(kù)時(shí)沾歪,將舊表數(shù)據(jù)copy到新表中,然后刪除舊表雾消。

國(guó)外有人開(kāi)源實(shí)現(xiàn)類(lèi)灾搏,親測(cè)可用


public class MigrationHelper {

    private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION = "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS";

    private static MigrationHelper instance;

    public static MigrationHelper getInstance() {

        if (instance == null) {

            instance = new MigrationHelper();

        }

        return instance;

    }

    private static List<String> getColumns(Database db, String tableName) {

        List<String> columns = new ArrayList<>();

        Cursor cursor = null;

        try {

            cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null);

            if (cursor != null) {

                columns = new ArrayList<>(Arrays.asList(cursor.getColumnNames()));

            }

        } catch (Exception e) {

            Log.v(tableName, e.getMessage(), e);

            e.printStackTrace();

        } finally {

            if (cursor != null)

                cursor.close();

        }

        return columns;

    }

    public void migrate(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {

        generateTempTables(db, daoClasses);

        DaoMaster.dropAllTables(db, true);

        DaoMaster.createAllTables(db, false);

        restoreData(db, daoClasses);

    }

    private void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {

        for (int i = 0; i < daoClasses.length; i++) {

            DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);

            String divider = "";

            String tableName = daoConfig.tablename;

            String tempTableName = daoConfig.tablename.concat("_TEMP");

            ArrayList<String> properties = new ArrayList<>();

            StringBuilder createTableStringBuilder = new StringBuilder();

            createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" (");

            for (int j = 0; j < daoConfig.properties.length; j++) {

                String columnName = daoConfig.properties[j].columnName;

                if (getColumns(db, tableName).contains(columnName)) {

                    properties.add(columnName);

                    String type = null;

                    try {

                        type = getTypeByClass(daoConfig.properties[j].type);

                    } catch (Exception exception) {

                        exception.printStackTrace();

                    }

                    createTableStringBuilder.append(divider).append(columnName).append(" ").append(type);

                    if (daoConfig.properties[j].primaryKey) {

                        createTableStringBuilder.append(" PRIMARY KEY");

                    }

                    divider = ",";

                }

            }

            createTableStringBuilder.append(");");

            Log.i("lxq", "創(chuàng)建臨時(shí)表的SQL語(yǔ)句: " + createTableStringBuilder.toString());

            db.execSQL(createTableStringBuilder.toString());

            StringBuilder insertTableStringBuilder = new StringBuilder();

            insertTableStringBuilder.append("INSERT INTO ").append(tempTableName).append(" (");

            insertTableStringBuilder.append(TextUtils.join(",", properties));

            insertTableStringBuilder.append(") SELECT ");

            insertTableStringBuilder.append(TextUtils.join(",", properties));

            insertTableStringBuilder.append(" FROM ").append(tableName).append(";");

            Log.i("lxq", "在臨時(shí)表插入數(shù)據(jù)的SQL語(yǔ)句:" + insertTableStringBuilder.toString());

            db.execSQL(insertTableStringBuilder.toString());

        }

    }

    private void restoreData(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {

        for (int i = 0; i < daoClasses.length; i++) {

            DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);

            String tableName = daoConfig.tablename;

            String tempTableName = daoConfig.tablename.concat("_TEMP");

            ArrayList<String> properties = new ArrayList();

            ArrayList<String> propertiesQuery = new ArrayList();

            for (int j = 0; j < daoConfig.properties.length; j++) {

                String columnName = daoConfig.properties[j].columnName;

                if (getColumns(db, tempTableName).contains(columnName)) {

                    properties.add(columnName);

                    propertiesQuery.add(columnName);

                } else {

                    try {

                        if (getTypeByClass(daoConfig.properties[j].type).equals("INTEGER")) {

                            propertiesQuery.add("0 as " + columnName);

                            properties.add(columnName);

                        }

                    } catch (Exception e) {

                        e.printStackTrace();

                    }

                }

            }

            StringBuilder insertTableStringBuilder = new StringBuilder();

            insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");

            insertTableStringBuilder.append(TextUtils.join(",", properties));

            insertTableStringBuilder.append(") SELECT ");

            insertTableStringBuilder.append(TextUtils.join(",", propertiesQuery));

            insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");

            StringBuilder dropTableStringBuilder = new StringBuilder();

            dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);

            Log.i("lxq", "插入正式表的SQL語(yǔ)句:" + insertTableStringBuilder.toString());

            Log.i("lxq", "銷(xiāo)毀臨時(shí)表的SQL語(yǔ)句:" + dropTableStringBuilder.toString());

            db.execSQL(insertTableStringBuilder.toString());

            db.execSQL(dropTableStringBuilder.toString());

        }

    }

    private String getTypeByClass(Class<?> type) throws Exception {

        if (type.equals(String.class)) {

            return "TEXT";

        }

        if (type.equals(Long.class) || type.equals(Integer.class) || type.equals(long.class) || type.equals(int.class)) {

            return "INTEGER";

        }

        if (type.equals(Boolean.class) || type.equals(boolean.class)) {

            return "BOOLEAN";

        }

        Exception exception = new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString()));

        exception.printStackTrace();

        throw exception;

    }

}

然后自己寫(xiě)一個(gè)Helper類(lèi),重寫(xiě)onUpgrade方法立润,在里邊實(shí)現(xiàn)數(shù)據(jù)庫(kù)的數(shù)據(jù)備份


public class MySqlLiteOpenHelper extends DaoMaster.OpenHelper{

    public MySqlLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {

        super(context, name);

    }

    @Override

    public void onCreate(Database db) {

        super.onCreate(db);

        /**

        * 這個(gè)方法

        * 1狂窑、在第一次打開(kāi)數(shù)據(jù)庫(kù)的時(shí)候才會(huì)走

        * 2、在清除數(shù)據(jù)之后再次運(yùn)行-->打開(kāi)數(shù)據(jù)庫(kù)桑腮,這個(gè)方法會(huì)走

        * 3泉哈、沒(méi)有清除數(shù)據(jù),不會(huì)走這個(gè)方法

        * 4破讨、數(shù)據(jù)庫(kù)升級(jí)的時(shí)候這個(gè)方法不會(huì)走

        */

    }

    @Override

    public void onUpgrade(Database db, int oldVersion, int newVersion) {

        super.onUpgrade(db, oldVersion, newVersion);

        /**

        * 1丛晦、第一次創(chuàng)建數(shù)據(jù)庫(kù)的時(shí)候,這個(gè)方法不會(huì)走

        * 2提陶、清除數(shù)據(jù)后再次運(yùn)行(相當(dāng)于第一次創(chuàng)建)這個(gè)方法不會(huì)走

        * 3烫沙、數(shù)據(jù)庫(kù)已經(jīng)存在,而且版本升高的時(shí)候隙笆,這個(gè)方法才會(huì)調(diào)用

        */

        if (oldVersion < newVersion) {

            MigrationHelper.getInstance().migrate(db, BibleLineAtionDBDao.class);

            MigrationHelper.getInstance().migrate(db, BibleInspirationDBDao.class);

        }

    }

    @Override

    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        super.onDowngrade(db, oldVersion, newVersion);

        /**

        * 執(zhí)行數(shù)據(jù)庫(kù)的降級(jí)操作

        * 1锌蓄、只有新版本比舊版本低的時(shí)候才會(huì)執(zhí)行

        * 2、如果不執(zhí)行降級(jí)操作撑柔,會(huì)拋出異常

        */

    }

}

初始化Greendao


public class DBRepository {

    public static final String DB_NAME = "data-db";//數(shù)據(jù)庫(kù)名稱(chēng)

    private static DaoSession mDaoSession;

    private static MySqlLiteOpenHelper mySqlLiteOpenHelper;

    /**

    * 初始化greenDao瘸爽,這個(gè)操作建議在Application初始化的時(shí)候添加;

    */

    public static void initDatabase(Context context) {

        if (context == null) {

            throw new IllegalArgumentException("You cannot start a load on a null Context");

        }

//        DatabaseOpenHelper mHelper = new DaoMaster.DevOpenHelper(context.getApplicationContext(), DB_NAME);

//        Database db = mHelper.getWritableDb();

        mySqlLiteOpenHelper = new MySqlLiteOpenHelper(context.getApplicationContext(),DB_NAME,null);

        Database db = mySqlLiteOpenHelper.getWritableDb();

        DaoMaster mDaoMaster = new DaoMaster(db);

        mDaoSession = mDaoMaster.newSession();

    }

    public static DaoSession getDaoSession() {

        return mDaoSession;

    }

}

在Application中實(shí)現(xiàn)初始化


private void initDataBase() {

        DBRepository.initDatabase(MyApplication.getContext());

    }

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末铅忿,一起剝皮案震驚了整個(gè)濱河市剪决,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖昼捍,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件识虚,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡妒茬,警方通過(guò)查閱死者的電腦和手機(jī)担锤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)乍钻,“玉大人肛循,你說(shuō)我怎么就攤上這事∫瘢” “怎么了多糠?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)浩考。 經(jīng)常有香客問(wèn)我夹孔,道長(zhǎng),這世上最難降的妖魔是什么析孽? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任搭伤,我火速辦了婚禮,結(jié)果婚禮上袜瞬,老公的妹妹穿的比我還像新娘怜俐。我一直安慰自己,他們只是感情好邓尤,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布拍鲤。 她就那樣靜靜地躺著,像睡著了一般汞扎。 火紅的嫁衣襯著肌膚如雪季稳。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,268評(píng)論 1 309
  • 那天澈魄,我揣著相機(jī)與錄音绞幌,去河邊找鬼。 笑死一忱,一個(gè)胖子當(dāng)著我的面吹牛莲蜘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播帘营,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼票渠,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了芬迄?” 一聲冷哼從身側(cè)響起问顷,我...
    開(kāi)封第一講書(shū)人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后杜窄,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體肠骆,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年塞耕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蚀腿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡扫外,死狀恐怖莉钙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情筛谚,我是刑警寧澤磁玉,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站驾讲,受9級(jí)特大地震影響蚊伞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吮铭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一时迫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧沐兵,春花似錦、人聲如沸便监。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)烧董。三九已至毁靶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間逊移,已是汗流浹背预吆。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胳泉,地道東北人拐叉。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像扇商,于是被迫代替她去往敵國(guó)和親凤瘦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容