GreenDao的使用与封装

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_31433525/article/details/79106059

官方api文档
SQLite可视化工具下载地址 Personal为免费版本

配置

在项目build.gradle中配置

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

在你要使用的模块下的build.gradle配置(我是直接在app模块下)

apply plugin: 'org.greenrobot.greendao'
greendao {
    // 指定数据库schema版本号,迁移等操作会用到
    schemaVersion 1
    // 通过gradle插件生成的数据库相关文件的包名,默认为你的entity所在的包名
    daoPackage 'com.example.greendao.dao'
    // 生成的数据库文件默认目录为:build/generated/source/greendao
    // 自定义生成数据库文件的目录,可以将生成的文件放到java目录中,而不是build中,这样就不用额外的设置资源目录了
    targetGenDir 'src/main/java'
}
dependencies {
    compile 'org.greenrobot:greendao:3.1.0'
}

greendao build配置
schemaVersion: 数据库schema版本,也可以理解为数据库版本号
daoPackage:设置DaoMaster 、DaoSession、Dao包名
targetGenDir:设置DaoMaster 、DaoSession、Dao目录
targetGenDirTest:设置生成单元测试目录
generateTests:设置自动生成单元测试用例
实体@Entity注解
schema:告知GreenDao当前实体属于哪个schema
active:标记一个实体处于活动状态,活动实体有更新、删除和刷新方法
nameInDb:在数据中使用的别名,默认使用的是实体的类名
indexes:定义索引,可以跨越多个列
createInDb:标记创建数据库表
基础属性注解
@Id :主键 Long型,可以通过@Id(autoincrement = true)设置自增长
@Property:设置一个非默认关系映射所对应的列名,默认是的使用字段名 举例:@Property (nameInDb=”name”)
@NotNul:设置数据库表当前列不能为空
@Transient :添加次标记之后不会生成数据库表的列
索引注解
@Index:使用@Index作为一个属性来创建一个索引,通过name设置索引别名,也可以通过unique给索引添加约束
@Unique:向数据库列添加了一个唯一的约束
关系注解
@ToOne:定义与另一个实体(一个实体对象)的关系
@ToMany:定义与多个实体对象的关系

使用

我的entity是写在com.example.greendao.entity包下,当编译的时候,系统会自动找到@Entity注解过的类,在com.example.greendao.dao下产生greendao所需的类(这个包在build.gradle中指定了daoPackage,否则会在build/generated/source/greendao下)。
为了测试方便,写了三种entity类:person,animal.house,body,PersonWithHouse类,默认的测试关系是person和animal是1:N,person和body是1:1,person和house是N:M,PersonWithHouse是person和house的联系。

@Entity
public class Person {
    //自增id类型只能是Long
    @Id(autoincrement = true)
    private Long id;
    @Property(nameInDb = "user")
    private String username;
    private int age;
    private Long bodyId;
    //一对一,将Person表中的bodyId与body的主键关联
    @ToOne(joinProperty = "bodyId")
    private Body body;
    //一对多
    @ToMany(referencedJoinProperty = "ownerId")
    private List<Animal> animals;
    //多对多
    @ToMany
    @JoinEntity(
            entity = PersonWithHouse.class,
            sourceProperty = "personId",
            targetProperty = "houseId"

    )
    private List<House> personWithHouse;
    //get,set方法编译后会自动产生
}
@Entity
public class Animal {
    @Id(autoincrement = true)
    private Long id;
    private Long ownerId;
    private String name;
}
@Entity
public class Body {
    @Id(autoincrement = true)
    private Long id;
    private int height;
    private int weight;
}
@Entity
public class House {
    @Id(autoincrement = true)
    private Long id;
    private String location;
    private String price;
      @ToMany
    @JoinEntity(
            entity = PersonWithHouse.class,
            sourceProperty = "houseId",
            targetProperty = "personId"
    )
    private List<Person> personList;
}
@Entity
public class PersonWithHouse {
    @Id(autoincrement = true)
    private Long id;
    private Long personId;
    private Long houseId;
}

封装

//在application中初始化MyDatabaseLoader.init(this,"greendao_db",null);
public class MyDatabaseLoader {
    private static DaoSession daoSession;
    public static void init(Context context,String databaseName,MyDataBaseOpenHelper.DataOpenHelper update){
            MyDataBaseOpenHelper openHelper = new MyDataBaseOpenHelper(context,databaseName,null,update);
            SQLiteDatabase database =  openHelper.getWritableDatabase();
            DaoMaster daoMaster =new DaoMaster(database);
            daoSession = daoMaster.newSession();
    }

    public static DaoSession getDaoSession() {
        return daoSession;
    }
}
//数据库升级操作封装,使用直接更改application初始化的MyDatabaseLoader 
public class MyDataBaseOpenHelper extends DaoMaster.OpenHelper {
    public DataOpenHelper dataOpenHelper;

    public MyDataBaseOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, DataOpenHelper upgrade) {
        super(context, name, factory);
        if(upgrade != null){
            dataOpenHelper = upgrade;
        }
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
       if(dataOpenHelper != null){
           dataOpenHelper.updata(db,oldVersion,newVersion);
       }
    }

    public interface DataOpenHelper{
        void updata(SQLiteDatabase db, int oldVersion, int newVersion);
    }
}

数据库操作的封装

public interface helperDao {
    //增加单条数据
    <T> void add(T bean);
    //增加list数据
    <T> void addAll(List<T> beanList);
    //通过id删除
    void delete(String id);
    //删除所有数据
    void deleteAll();
    //通过id查找
    <T> T  query(String id);
    //通过id修改
    <T> void updata(T bean);
}
public class PersonDaoHelper implements helperDao{
    private PersonDao personDao;
    private static PersonDaoHelper personDaoHelper;
    public PersonDaoHelper(){
        personDao = MyDatabaseLoader.getDaoSession().getPersonDao();
    }
    public static PersonDaoHelper getInstance(){
        if(personDaoHelper == null ){
            personDaoHelper = new PersonDaoHelper();
        }
        return personDaoHelper;
    }

    @Override
    public <T> void add(T bean) {
        if(personDao != null  && bean != null){
            personDao.insert((Person) bean);
        }
    }

    @Override
    public <T> void addAll(List<T> beanList) {
        if(personDao !=null &&beanList != null){
            personDao.insertInTx((List<Person>) beanList);
        }
    }

    @Override
    public void delete(String id) {
        if(personDao !=null && id  != null && !"".equals(id)){
            personDao.deleteByKey(Long.valueOf(id));
        }

    }

    @Override
    public void deleteAll() {
        if(personDao !=null){
            personDao.deleteAll();
        }
    }

    @Override
    public <T> void updata(T bean) {
        if(personDao !=null && bean != null){
            personDao.update((Person) bean);
        }
    }

    @Override
    public List<Person> query(String id) {
        if(personDao !=null && id  != null && !"".equals(id)){
          List<Person> list=personDao.queryBuilder().where(PersonDao.Properties.Id.eq(id)).list();
          return list;
        }
        return null;
    }

}

一张表一个helper类,其他以此类推,所有会有如下类:AnimalDaoHelper,BodyDaoHelper,HouseDaoHelper,PersonDaoHelper,PersonWithHouseDaoHelper

一对一

 Person person =new Person();
 person.setUsername("人"+j);
 person.setAge(18);
 Body body = new Body();
 body.setHeight(180);
 body.setWeight(170);
 BodyDaoHelper.getinstance().add(body);
 person.setBody(body);
 PersonDaoHelper.getInstance().add(person);

一对多

for(int j=0;j<4;j++){
            Person person =new Person();
            person.setUsername("人"+j);
            person.setAge(18);
            Body body = new Body();
            body.setHeight(180);
            body.setWeight(170);
            BodyDaoHelper.getinstance().add(body);
            person.setBody(body);
            PersonDaoHelper.getInstance().add(person);
            for(int i=0;i<3;i++){
                Animal animal =new Animal();
                animal.setName("狗"+i);
                //保存操作完成之后可以从缓存中直接取出插入的person
                animal.setOwnerId(person.getId());
                AnimalDaoHelper.getInsteance().add(animal);
            }
        }

多对多

List<House> houseList = new ArrayList<>();
        List<Person> personList = new ArrayList<>();
        for(int j=0;j<4;j++){
            Person person =new Person();
            person.setUsername("人"+j);
            person.setAge(18);
            personList.add(person);
        }
        PersonDaoHelper.getInstance().addAll(personList);
        for(int j=0;j<4;j++){
            House house =new House();
            house.setLocation("北京"+j);
            house.setPrice("10000");
            houseList.add(house);
        }
        HouseDaoHelper.getInstance().addAll(houseList);

        //person1选house1,house2
        //house3有person2,person3
        List<PersonWithHouse> personWithHouseList = new ArrayList<>();
        PersonWithHouse personWithHouse = new PersonWithHouse(null,personList.get(1).getId(),houseList.get(1).getId());
        personWithHouseList.add(personWithHouse);
        personWithHouse = new PersonWithHouse(null,personList.get(1).getId(),houseList.get(2).getId());
        personWithHouseList.add(personWithHouse);
        personWithHouse = new PersonWithHouse(null,personList.get(2).getId(),houseList.get(3).getId());
        personWithHouseList.add(personWithHouse);
        personWithHouse = new PersonWithHouse(null,personList.get(3).getId(),houseList.get(3).getId());
        personWithHouseList.add(personWithHouse);
        PersonWithHouseDaoHelper.getInstance().addAll(personWithHouseList);

PersonDaoHelper.getInstance().delete("3");

改查

由于更改需要先查询所以就写在了一起

扫描二维码关注公众号,回复: 6781767 查看本文章
//查询
 List<Person> personList = PersonDaoHelper.getInstance().query("2");
        if(personList !=null){
            Person person = personList.get(0);
            person.setUsername("改动");
            //更改
            PersonDaoHelper.getInstance().updata(person);
        }

注:所有的数据库操作只对单表有效,关联的表不会有影响

数据库升级

默认是删除原数据库创建新的数据库,但这样数据将无法保留,所以自定义一个升级类。MyDataBaseOpenHelper
原理是
1 把旧表改为临时表
2 建立新表
3 临时表数据写入新表,删除临时表
直接使用了开源库,GreenDaoUpgradeHelper
核心的类就是

public final class MigrationHelper {
    public static        boolean DEBUG              = false;
    private static       String  TAG                = "MigrationHelper";
    private static final String  SQLITE_MASTER      = "sqlite_master";
    private static final String  SQLITE_TEMP_MASTER = "sqlite_temp_master";
    private static WeakReference<ReCreateAllTableListener> weakListener;

    public interface ReCreateAllTableListener {
        void onCreateAllTables(Database db, boolean ifNotExists);

        void onDropAllTables(Database db, boolean ifExists);
    }

    public static void migrate(SQLiteDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        printLog("【The Old Database Version】" + db.getVersion());
        Database database = new StandardDatabase(db);
        migrate(database, daoClasses);
    }

    public static void migrate(SQLiteDatabase db, ReCreateAllTableListener listener, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        weakListener = new WeakReference<>(listener);
        migrate(db, daoClasses);
    }

    public static void migrate(Database database, ReCreateAllTableListener listener, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        weakListener = new WeakReference<>(listener);
        migrate(database, daoClasses);
    }

    public static void migrate(Database database, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        printLog("【Generate temp table】start");
        generateTempTables(database, daoClasses);
        printLog("【Generate temp table】complete");

        ReCreateAllTableListener listener = null;
        if (weakListener != null) {
            listener = weakListener.get();
        }

        if (listener != null) {
            listener.onDropAllTables(database, true);
            printLog("【Drop all table by listener】");
            listener.onCreateAllTables(database, false);
            printLog("【Create all table by listener】");
        } else {
            dropAllTables(database, true, daoClasses);
            createAllTables(database, false, daoClasses);
        }
        printLog("【Restore data】start");
        restoreData(database, daoClasses);
        printLog("【Restore data】complete");
    }

    private static void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        for (int i = 0; i < daoClasses.length; i++) {
            String tempTableName = null;

            DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
            String    tableName = daoConfig.tablename;
            if (!isTableExists(db, false, tableName)) {
                printLog("【New Table】" + tableName);
                continue;
            }
            try {
                tempTableName = daoConfig.tablename.concat("_TEMP");
                StringBuilder dropTableStringBuilder = new StringBuilder();
                dropTableStringBuilder.append("DROP TABLE IF EXISTS ").append(tempTableName).append(";");
                db.execSQL(dropTableStringBuilder.toString());

                StringBuilder insertTableStringBuilder = new StringBuilder();
                insertTableStringBuilder.append("CREATE TEMPORARY TABLE ").append(tempTableName);
                insertTableStringBuilder.append(" AS SELECT * FROM ").append(tableName).append(";");
                db.execSQL(insertTableStringBuilder.toString());
                printLog("【Table】" + tableName + "\n ---Columns-->" + getColumnsStr(daoConfig));
                printLog("【Generate temp table】" + tempTableName);
            } catch (SQLException e) {
                Log.e(TAG, "【Failed to generate temp table】" + tempTableName, e);
            }
        }
    }

    private static boolean isTableExists(Database db, boolean isTemp, String tableName) {
        if (db == null || TextUtils.isEmpty(tableName)) {
            return false;
        }
        String dbName = isTemp ? SQLITE_TEMP_MASTER : SQLITE_MASTER;
        String sql    = "SELECT COUNT(*) FROM " + dbName + " WHERE type = ? AND name = ?";
        Cursor cursor = null;
        int    count  = 0;
        try {
            cursor = db.rawQuery(sql, new String[]{"table", tableName});
            if (cursor == null || !cursor.moveToFirst()) {
                return false;
            }
            count = cursor.getInt(0);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return count > 0;
    }

    private static String getColumnsStr(DaoConfig daoConfig) {
        if (daoConfig == null) {
            return "no columns";
        }
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < daoConfig.allColumns.length; i++) {
            builder.append(daoConfig.allColumns[i]);
            builder.append(",");
        }
        if (builder.length() > 0) {
            builder.deleteCharAt(builder.length() - 1);
        }
        return builder.toString();
    }

    private static void dropAllTables(Database db, boolean ifExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {
        reflectMethod(db, "dropTable", ifExists, daoClasses);
        printLog("【Drop all table by reflect】");
    }

    private static void createAllTables(Database db, boolean ifNotExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {
        reflectMethod(db, "createTable", ifNotExists, daoClasses);
        printLog("【Create all table by reflect】");
    }

    /**
     * dao class already define the sql exec method, so just invoke it
     */
    private static void reflectMethod(Database db, String methodName, boolean isExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {
        if (daoClasses.length < 1) {
            return;
        }
        try {
            for (Class cls : daoClasses) {
                Method method = cls.getDeclaredMethod(methodName, Database.class, boolean.class);
                method.invoke(null, db, isExists);
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    private static 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");

            if (!isTableExists(db, true, tempTableName)) {
                continue;
            }

            try {
                // get all columns from tempTable, take careful to use the columns list
                List<String>      columns    = getColumns(db, tempTableName);
                ArrayList<String> properties = new ArrayList<>(columns.size());
                for (int j = 0; j < daoConfig.properties.length; j++) {
                    String columnName = daoConfig.properties[j].columnName;
                    if (columns.contains(columnName)) {
                        properties.add("`" + columnName + "`");
                    }
                }
                if (properties.size() > 0) {
                    final String columnSQL = TextUtils.join(",", properties);

                    StringBuilder insertTableStringBuilder = new StringBuilder();
                    insertTableStringBuilder.append("REPLACE INTO ").append(tableName).append(" (");
                    insertTableStringBuilder.append(columnSQL);
                    insertTableStringBuilder.append(") SELECT ");
                    insertTableStringBuilder.append(columnSQL);
                    insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");
                    db.execSQL(insertTableStringBuilder.toString());
                    printLog("【Restore data】 to " + tableName);
                }
                StringBuilder dropTableStringBuilder = new StringBuilder();
                dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);
                db.execSQL(dropTableStringBuilder.toString());
                printLog("【Drop temp table】" + tempTableName);
            } catch (SQLException e) {
                Log.e(TAG, "【Failed to restore data from temp table 】" + tempTableName, e);
            }
        }
    }

    private static List<String> getColumns(Database db, String tableName) {
        List<String> columns = null;
        Cursor       cursor  = null;
        try {
            cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 0", null);
            if (null != cursor && cursor.getColumnCount() > 0) {
                columns = Arrays.asList(cursor.getColumnNames());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null)
                cursor.close();
            if (null == columns)
                columns = new ArrayList<>();
        }
        return columns;
    }

    private static void printLog(String info) {
        if (DEBUG) {
            Log.d(TAG, info);
        }
    }
}

要升级直接在application初始化是调用

MyDatabaseLoader.init(this, "greendao_db", new MyDataBaseOpenHelper.DataOpenHelper() {
            @Override
            public void updata(SQLiteDatabase db, int oldVersion, int newVersion) {
                if(oldVersion ==1 && newVersion == 2){
                    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);
                        }
                    }, PersonDao.class);//person类更改了,还有其他的直接在后面添加
                }
            }
        });

在build.gradle文件下更改版本号schemaVersion,运行之后就是新的表了。

猜你喜欢

转载自blog.csdn.net/qq_31433525/article/details/79106059