greenDao使用

2017-07-03  本文已影响0人  Erzyb

网络资源整理自用,非原创。

  1. 配置
//project配置
buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.2'
        classpath 'org.greenrobot:greendao-gradle-plugin:3.1.0'
    }
}
//module配置
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao'
android {
    greendao {
        schemaVersion 1    //数据库版本
        targetGenDir '*******'    //生成DaoMaster类文件夹
        daoPackage   '**********'  //生成DaoMaster类包名
    }
dependencies {
    compile 'org.greenrobot:greendao:3.1.0'
}
  1. 表创建
@Entity(nameInDb = "Book")
public class Book {
    @Id(autoincrement = true)
    @Property(nameInDb = "no")
    //@Unique
    private String no;
    @Property(nameInDb = "title")
    //@Transient
    private String title;
    @Property(nameInDb = "author")
    //@NotNull
    private String author;}```
@Entity 用于标识这是一个需要Greendao帮我们生成代码的bean
@Id 标明主键,括号里可以指定是否自增
@Property 用于设置属性在[数据库](http://lib.csdn.net/base/mysql)中的列名(默认不写就是保持一致)
@NotNull 非空
@Transient 标识这个字段是自定义的不会创建到数据库表里
@Unique 添加唯一约束
  make projeck后会自动添加seter,geter以及构造函数。并且会新加三个类:
  -  BookDao
  -  DaoMaster
  -  DaoSession
2. 封装

//网上找的封装
public class DBManager {
private DaoMaster mDaoMaster;
private DaoSession mDaoSession;
private static DBManager mInstance; //单例

private DBManager(){
    if (mInstance == null) {
        DaoMaster.DevOpenHelper devOpenHelper = new MergeDevOpenHelper(new GreenDaoContext(), "******.db");
        mDaoMaster = new DaoMaster(devOpenHelper.getWritableDatabase());
        mDaoSession = mDaoMaster.newSession();
    }
}

public static DBManager getInstance() {
    if (mInstance == null) {
        synchronized (DBManager.class) {//保证异步处理安全操作
            if (mInstance == null) {
                mInstance = new DBManager();
            }
        }
    }
    return mInstance;
}

public DaoMaster getMaster() {
    return mDaoMaster;
}
public DaoSession getSession() {
    return mDaoSession;
}
public DaoSession getNewSession() {
    mDaoSession = mDaoMaster.newSession();
    return mDaoSession;
}

}

1. 使用

//在application的onCreate中调用getInstance
DBManager.getInstance();
//可以再封装,调用api实现增删改查
DBManager.getInstance().getSession().getBookDao().queryBuilder().list();//查询book表中所有数据

5. 升级和迁移
  普通升级直接修改数据库版本号就可以了,但是默认实现会删除所有数据,重新创建数据库表格。所以需要自己实现升级。

public class MergeDevOpenHelper extends DaoMaster.OpenHelper{
public MergeDevOpenHelper(Context context, String name) {
super(context, name);
}

@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
    MigrationHelper.getInstance().migrate(db, BookDao.class);
}

}


//类是从github中copy出来的,非原创。。。。。
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;
}

public void migrate(Database db, Class... daoClasses) {
    generateTempTables(db, daoClasses);
    DaoMaster.dropAllTables(db, true);
    DaoMaster.createAllTables(db, false);
    restoreData(db, daoClasses);
}

private void generateTempTables(Database db, Class... 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 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) {
                }

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

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

                divider = ",";
            }
        }
        createTableStringBuilder.append(");");

        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(";");

        db.execSQL(insertTableStringBuilder.toString());
    }
}

private void restoreData(Database db, Class... 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 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 ").append(tempTableName);

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

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

private static List getColumns(Database db, String tableName) {
    List 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 class GreenDaoContext extends ContextWrapper {
private String currentUserId = "greendao";//一般用来针对一个用户一个数据库,以免数据混乱问题
private Context mContext;

public GreenDaoContext() {
    super(BaseApp.gContext);
    this.mContext = BaseApp.gContext;
    //        this.currentUserId = "greendao";//初始化
}

/**
 * 获得数据库路径,如果不存在,则创建对象
 *
 * @param dbName
 */
@Override
public File getDatabasePath(String dbName) {
    String dbDir = "";//指定数据库路径
    if (TextUtils.isEmpty(dbDir)){
        Log.e("SD卡管理:", "SD卡不存在,请加载SD卡");
        return null;
    }
    File baseFile = new File(dbDir);
    // 目录不存在则自动创建目录
    if (!baseFile.exists()){
        baseFile.mkdirs();
    }
    StringBuffer buffer = new StringBuffer();
    buffer.append(baseFile.getPath());
    buffer.append(File.separator);

// buffer.append(currentUserId);
dbDir = buffer.toString();// 数据库所在目录
// buffer.append(File.separator);
// buffer.append(dbName+"_"+currentUserId);//也可以采用此种方式,将用户id与表名联系到一块命名
buffer.append(dbName);
String dbPath = buffer.toString();// 数据库路径
LogUtil.e(LogUtil.getLogTag()+dbPath);
// 判断目录是否存在,不存在则创建该目录
File dirFile = new File(dbDir);
if (!dirFile.exists()){
dirFile.mkdirs();
}
// 数据库文件是否创建成功
boolean isFileCreateSuccess = false;
// 判断文件是否存在,不存在则创建该文件
File dbFile = new File(dbPath);
if (!dbFile.exists()) {
try {
LogUtil.e(LogUtil.getLogTag()+"创建db");
isFileCreateSuccess = dbFile.createNewFile();// 创建文件
} catch (IOException e) {
e.printStackTrace();
}
} else
isFileCreateSuccess = true;
// 返回数据库文件对象
if (isFileCreateSuccess)
return dbFile;
else
return super.getDatabasePath(dbName);
}

/**
 * 重载这个方法,是用来打开SD卡上的数据库的,android 2.3及以下会调用这个方法。
 *
 * @param name
 * @param mode
 * @param factory
 */
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode,SQLiteDatabase.CursorFactory factory) {
    SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), factory);
    return result;
}

/**
 * Android 4.0会调用此方法获取数据库。
 *
 * @param name
 * @param mode
 * @param factory
 * @param errorHandler
 * @see android.content.ContextWrapper#openOrCreateDatabase(java.lang.String, int,
 * android.database.sqlite.SQLiteDatabase.CursorFactory,
 * android.database.DatabaseErrorHandler)
 */
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory,DatabaseErrorHandler errorHandler) {
    SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), factory);

    return result;
}

}

上一篇下一篇

猜你喜欢

热点阅读