GreenDao2.0使用詳解

介紹

GreenDAO是一個對象關系映射(ORM)的框架,能夠提供相關接口,通過操作對象的方式去操作關系型數據庫。GreenDao官網介紹: greenDAO is a light & fast ORM solution for Android that maps objects to SQLite databases.

greenDao作為java對象和SQLite數據庫之間的橋梁

GreenDao的優勢
greenDao與OrmLite、ActiveAndroid對比
  1. 輕量級
  2. 增刪改查操作快速
  3. 內存開銷小,性能好
  4. Api接口完善,方便初學者使用
GreenDao2.0配置

在gradle中引入:

compile 'de.greenrobot:greendao:2.0.0'

GreenDao2.0使用
  • 創建本地數據庫及表
    新建一java工程,導入greendao-generator-1.3.1.jar到libs中,main文件中寫:
    public class ExampleDaoGenerator {
    public static void main(String[] args) throws Exception {
    //第一個參數是數據庫版本號,第二個參數是包名
    Schema schema = new Schema(version, "你的包名路徑");
    //給數據庫新增一張表
    addMessage(schema);
    //第二個參數是文件生成路徑
    new DaoGenerator().generateAll(schema, LocalConstants.CODE_PATH);
    }
    private static void addMessage(Schema schema) {
    //表實體,會對應生成一張表
    Entity note = schema.addEntity("MessageEntity");
    //給表添加一個主鍵
    note.addStringProperty("msgId").primaryKey().notNull();
    //boolean類型字段,對應列名
    note.addBooleanProperty("isRead");
    //字符類型字段,對應列名
    note.addStringProperty("createTime");
    }
    }
    執行Main()方法,數據庫映射文件將會在LocalConstants.CODE_PATH路徑下生成。

  • 數據庫的使用(表的增刪改查)
    public class DbHelper {
    private final static String DB_NAME = "xxx.db";
    private static volatile DbHelper dbHelper;
    private DaoSession daoSession;
    private DaoMaster daoMaster;
    private MessageEntityDao messageEntityDao;
    public static DbHelper getInstance() {
    if (null == dbHelper) {
    synchronized (DbHelper.class) {
    if (null == dbHelper) {
    dbHelper = new DbHelper();
    dbHelper.daoSession = dbHelper.getDaoSession(XxxApplication.getInstance());
    dbHelper.messageEntityDao = dbHelper.daoSession.getMessageEntityDao();
    }
    }
    }
    return dbHelper;
    }
    private DbHelper() {

        }
    
      private DaoSession getDaoSession(Context context) {
        if (daoSession == null) {
          if (daoMaster == null) {
              daoMaster = getDaoMaster(context);
          }
          daoSession = daoMaster.newSession();
        }
        return daoSession;
      }
      private DaoMaster getDaoMaster(Context context) {
      if (daoMaster == null) {
          DaoMaster.OpenHelper helper = new DaoMaster.DevOpenHelper(context, DB_NAME, null);
          daoMaster = new DaoMaster(helper.getWritableDatabase());
      }
      return daoMaster;
    }
    //保存一條消息
    public long saveMessageEntity(MessageEntity messageEntity) {
      if (null == messageEntity) {
          return -1;
      }
      long result = -1;
      try {
          result = messageEntityDao.insertOrReplace(messageEntity);
      } catch (ClassCastException ex) {
          MLog.e("ClassCastException", "ClassCastException");
      } catch (Exception ex) {
          ex.printStackTrace();
      }
      return result;
    }
    //查詢未讀消息數
    public int getNoReadMsg() {
      try {
          return messageEntityDao.queryBuilder().where(MessageEntityDao.Properties.IsRead.eq(false)).build().list().size();
      } catch (Exception e) {
          e.printStackTrace();
          return 0;
      }
    }
    //查消息類型對應的未讀消息條數
    public int getNoReadMsgCountByMsgType(String msgType) {
      try {
          return messageEntityDao.queryBuilder().where( MessageEntityDao.Properties.MsgType.eq(msgType), MessageEntityDao.Properties.IsRead.eq(false)).build().list().size();
      } catch (Exception e) {
          e.printStackTrace();
          return 0;
      }
    }
    //查詢消息
    public MessageEntity getMsgByMsgId(String msgId) {
        try {
          return messageEntityDao.queryBuilder().where(MessageEntityDao.Properties.MsgId.eq(msgId)).build().unique();
          } catch (Exception e) {
          e.printStackTrace();
          return null;
          }
      }
    }
    

說明:
使用DevOpenHelper打開數據庫
DaoMaster.DevOpenHelper helper = new DevOpenHelper(context,"xxx.db",null);
我們查看下DevOpenHelper內容
public static class DevOpenHelper extends OpenHelper {
public DevOpenHelper(Context context, String name, CursorFactory factory) {
super(context, name, factory);
}

  @Override
  public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
      Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
      dropAllTables(db, true);
      onCreate(db);
  }
  }

可以發現,當數據庫版本更新時,會執行onUpgrade方法,先刪除原有的數據表,再新建表。

數據庫升級

當我們的app版本升級時,當對本地數據庫表結構修改時,就有必要對本地數據庫升級。我們只需要修改下DaoMaster文件中的SCHEMA_VERSION常量(增1),它就會執行onUpgrade()。
public class DaoMaster extends AbstractDaoMaster {
public static final int SCHEMA_VERSION = 128;
public static void createAllTables(SQLiteDatabase db, boolean ifNotExists) {
MessageEntityDao.createTable(db, ifNotExists);
}
......
}
有時我們并不想把原有的表數據也刪除,那要怎么做呢?
其核心思路是

  1. 把舊表改為臨時表
  2. 建立新表
  3. 臨時表數據寫入新表,刪除臨時表

代碼實現:
/**
*表字段有改變的時候需要用到合并數據
*Created by wangfengkai on 17/3/11.
*Github:https://github.com/github/jxwangfengkai
*/
public class DbOpenHelper extends DaoMaster.OpenHelper {
public DbOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
      //操作數據庫的更新
      MigrationHelper.getInstance().migrate(sqLiteDatabase, MessageEntityDao.class);
    }
  }

  /**
   * MigrationHelper類
   */
  public class MigrationHelper {
      private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION = "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS";
      private static final String TAG = "MigrationHelper";
      private static volatile MigrationHelper instance;

      public static MigrationHelper getInstance() {
          if (instance == null) {
              instance = new MigrationHelper();
          }
          return instance;
      }

      public void migrate(SQLiteDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
          generateTempTables(db, daoClasses);
          DaoMaster.dropAllTables(db, true);
          DaoMaster.createAllTables(db, false);
          restoreData(db, daoClasses);
      }

      private void generateTempTables(SQLiteDatabase 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) {
                          Log.e(TAG, "CrashType:" + daoConfig.properties[j].type);
                          exception.printStackTrace();
                      }
                      createTableStringBuilder.append(divider).append(columnName).append(" ").append(type);

                      if (daoConfig.properties[j].primaryKey) {
                          createTableStringBuilder.append(" PRIMARY KEY");
                      }

                      divider = ",";
                  }
              }
              createTableStringBuilder.append(");");
              String createSql = createTableStringBuilder.toString();
              if (!createSql.contains("();")) {
                  //說明沒有表
                  db.execSQL(createSql);
                  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(";");

                  String insertTableSql = insertTableStringBuilder.toString();
                  Log.e(TAG, daoConfig.tablename + "__insertTableSql:" + insertTableSql);
                  db.execSQL(insertTableSql);
              }
          }
      }

      private void restoreData(SQLiteDatabase 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();

              for (int j = 0; j < daoConfig.properties.length; j++) {
                  String columnName = daoConfig.properties[j].columnName;

                  if (getColumns(db, tempTableName).contains(columnName)) {
                      properties.add(columnName);
                  }
              }

              StringBuilder insertTableStringBuilder = new StringBuilder();

              insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");
              insertTableStringBuilder.append(TextUtils.join(",", properties));
              insertTableStringBuilder.append(") SELECT ");
              insertTableStringBuilder.append(TextUtils.join(",", properties));
              insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");

              StringBuilder dropTableStringBuilder = new StringBuilder();

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

              String insertSQL = insertTableStringBuilder.toString();
              if (properties.size() > 0) {
                  Log.e(TAG, daoConfig.tablename + "__restoreData__insertSQL:" + insertSQL);
                  db.execSQL(insertSQL);
              }
              String dropTableSql = dropTableStringBuilder.toString();
              Log.e(TAG, daoConfig.tablename + "__restoreData__dropTableSql:" + dropTableSql);
              db.execSQL(dropTableSql);
          }
      }

      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) || type.equals(Boolean.class) || type.equals(boolean.class)) {
              return "INTEGER";
          }

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

      private static List<String> getColumns(SQLiteDatabase 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;
      }
  }

所以,當需要數據庫升級時,我們使用
DbOpenHelper helper = new DbOpenHelper(context,"xxx.db",null);
來打開數據庫。
講到這里,GreenDao2.0的使用基本已經完了,下一篇,我將為大家講解GreenDao3.0的優化及使用。
喜歡就點個贊哦。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • http://jinnianshilongnian.iteye.com/blog/2022468 Realm數據...
    天之大任閱讀 290評論 0 0
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,933評論 18 139
  • 前言: 上一篇簡介了greendao的數據庫的接入以及簡單的操作,既然涉及到數據庫中的數據,那就必須考慮到加密問題...
    Smile__EveryDay閱讀 2,244評論 0 8
  • 以前開發用到數據庫時,基本上都是用android原生的sql語句,寫那些語句時稍有不慎,就給你拋出一個except...
    BlainPeng閱讀 7,701評論 2 12
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,765評論 18 399