【Android】ORM框架greenDao 3

作者:邹峰立,微博:zrunker,邮箱:zrunker@yahoo.com,微信公众号:书客创作,个人平台:www.ibooker.cc

本文选自书客创作平台第10篇文章。阅读原文

书客创作

在Android中,对SQLite数据库的操作,是一件很频繁的事情。而greenDao是Android中SQLite数据库的一个ORM框架,它以占用资源少,效率高,而得到广泛使用。

greenDao 3相对于greenDao 2的使用还是有一些区别的。greenDao 3更加精简,采用注解的方式。那么greenDao 3究竟该如何使用呢?

greenDao 3的使用

1、配置app的gradle文件

dependencies {
    /*数据库orm-greendao*/
    implementation 'org.greenrobot:greendao:3.2.2'
}
apply plugin: 'org.greenrobot.greendao' // apply plugin
// 配置数据库的信息
greendao {
    schemaVersion 1 // 对应当前数据库版本
    daoPackage 'cc.ibooker.greendao' // 由GreenDao自动生成代码所在的包名,默认的是在项目包下面新建一个gen。
    targetGenDir 'src/main/java' // 设置自动生成代码的目录
}

2、配置module的gradle文件

buildscript {
    dependencies {
        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
    }
}

注意:github中提示添加maven仓库,但是android studio 项目已经默认包含了jcenter仓库,而jcenter仓库就是maven仓库的一个分支,因此我们不要再添加仓库,直接添加classPath即可。

3、定义实体类,这里定义两个实体类User和Friend。

/**
 * 用户表+实体类
 * Created by 邹峰立 on 2017/9/23 0023.
 */
@Entity(
        // active表示update/delete/refresh 方法是否自动生成,默认为false
        active = true,
        // createInDb表示是否在数据库中创建该表,默认为true
        createInDb = true,
        // generateConstructors表示是否生成构造方法(一般有两个,一个有参数,一个无参数),默认为true
        generateConstructors = true,
        // indexes表示数据表查询返回数据默认排序,name中的字段是该实体在数据表中的列名,value表示改实体的真实名称,unique表示是否唯一(默认为false)
        indexes = {@Index(value = "_id ASC"),@Index(value = "uId DESC")},
        // nameInDb表示数据表的名称默认为实体类的名称
        nameInDb = "t_user",
        // 表示是否生成get/set方法,默认为true
        generateGettersSetters = true
)
public class User  {
    @Id(autoincrement = true)
    @Property(nameInDb = "_id")
    private Long _id;
    @NotNull
    @Unique
    @Property(nameInDb = "u_id")
    private long uId;
    @Property(nameInDb = "u_realname")
    private String uRealName;
    @Property(nameInDb = "u_sex")
    private String uSex;
    @Property(nameInDb = "u_birthday")
    private String uBirthday;
    @Property(nameInDb = "u_height")
    private float uHeight;
    @Property(nameInDb = "u_weight")
    private float uWeight;
    @Property(nameInDb = "u_domicile")
    private String uDomicile;
    @Property(nameInDb = "u_phone")
    private long uPhone;
    @Property(nameInDb = "u_email")
    private String uEmail;
    @Property(nameInDb = "u_weibo")
    private String uWeibo;

    // 一堆多
    @ToMany(referencedJoinProperty = "fUid")
    private List<Friend> friends;

    public User() {
        super();
    }

    public User(long uId, String uRealName, String uSex, String uBirthday, float uHeight, float uWeight, String uDomicile, long uPhone, String uEmail, String uWeibo) {
        this.uId = uId;
        this.uRealName = uRealName;
        this.uSex = uSex;
        this.uBirthday = uBirthday;
        this.uHeight = uHeight;
        this.uWeight = uWeight;
        this.uDomicile = uDomicile;
        this.uPhone = uPhone;
        this.uEmail = uEmail;
        this.uWeibo = uWeibo;
    }

    public long getuId() {
        return uId;
    }

    public void setuId(long uId) {
        this.uId = uId;
    }

    public String getuRealName() {
        return uRealName;
    }

    public void setuRealName(String uRealName) {
        this.uRealName = uRealName;
    }

    public String getuSex() {
        return uSex;
    }

    public void setuSex(String uSex) {
        this.uSex = uSex;
    }

    public String getuBirthday() {
        return uBirthday;
    }

    public void setuBirthday(String uBirthday) {
        this.uBirthday = uBirthday;
    }

    public float getuHeight() {
        return uHeight;
    }

    public void setuHeight(float uHeight) {
        this.uHeight = uHeight;
    }

    public float getuWeight() {
        return uWeight;
    }

    public void setuWeight(float uWeight) {
        this.uWeight = uWeight;
    }

    public String getuDomicile() {
        return uDomicile;
    }

    public void setuDomicile(String uDomicile) {
        this.uDomicile = uDomicile;
    }

    public long getuPhone() {
        return uPhone;
    }

    public void setuPhone(long uPhone) {
        this.uPhone = uPhone;
    }

    public String getuEmail() {
        return uEmail;
    }

    public void setuEmail(String uEmail) {
        this.uEmail = uEmail;
    }

    public String getuWeibo() {
        return uWeibo;
    }

    public void setuWeibo(String uWeibo) {
        this.uWeibo = uWeibo;
    }

    @Override
    public String toString() {
        return "User{" +
                "uId=" + uId +
                ", uRealName='" + uRealName + '\'' +
                ", uSex='" + uSex + '\'' +
                ", uBirthday='" + uBirthday + '\'' +
                ", uHeight=" + uHeight +
                ", uWeight=" + uWeight +
                ", uDomicile='" + uDomicile + '\'' +
                ", uPhone=" + uPhone +
                ", uEmail='" + uEmail + '\'' +
                ", uWeibo='" + uWeibo + '\'' +
                '}';
    }
}
/**
 * 朋友表+实体类
 * Created by 邹峰立 on 2017/9/23 0023.
 */
@Entity(
        // active表示update/delete/refresh 方法是否自动生成,默认为false
        active = true,
        // createInDb表示是否在数据库中创建该表,默认为true
        createInDb = true,
        // generateConstructors表示是否生成构造方法(一般有两个,一个有参数,一个无参数),默认为true
        generateConstructors = true,
        // indexes表示数据表查询返回数据默认排序,name中的字段是该实体在数据表中的列名,value表示改实体的真实名称,unique表示是否唯一(默认为false)
        indexes = {@Index(value = "_id ASC"),@Index(value = "fId DESC")},
        // nameInDb表示数据表的名称默认为实体类的名称
        nameInDb = "t_friend",
        // 表示是否生成get/set方法,默认为true
        generateGettersSetters = true
)
public class Friend {
    @Id(autoincrement = true)
    @Property(nameInDb = "_id")
    private Long _id;
    @NotNull
    @Unique
    @Property(nameInDb = "f_id")
    private long fId;// ID
    @NotNull
    @Property(nameInDb = "f_gname")
    private String fGname;// 组名
    @NotNull
    @Property(nameInDb = "f_uid")
    private long fUid;// 用户ID

    @ToOne(joinProperty = "fUid")
    private User user;

    public Friend() {
        super();
    }

    public Friend(long fId, String fGname, long fUid) {
        this.fId = fId;
        this.fGname = fGname;
        this.fUid = fUid;
    }

    public long getfId() {
        return fId;
    }

    public void setfId(long fId) {
        this.fId = fId;
    }

    public String getfGname() {
        return fGname;
    }

    public void setfGname(String fGname) {
        this.fGname = fGname;
    }

    public long getfUid() {
        return fUid;
    }

    public void setfUid(long fUid) {
        this.fUid = fUid;
    }

    @Override
    public String toString() {
        return "Friend{" +
                "fId=" + fId +
                ", fGname='" + fGname + '\'' +
                ", fUid=" + fUid +
                '}';
    }
}

4、greenDao注解解释

@Entity   用于描述实体类名,其中active表示update/delete/refresh 方法是否自动生成,默认为false.
    createInDb   表示是否在数据库中创建表,默认为true,如果为false,将不创建该表.
    generateConstructors   表示是否自动生成构造方法(一个有参构造,一个无参构造).
    indexes   表示制定查询数据返回的默认排序规则.(@Index中的value制定排序的数据表中的列明加上排序规则即(ASC/DESC),
    name   表示......,unique   表示是否唯一即SQL中的去重复
    如果按照多个字段来排序可以这样(比如(indexes={@Index(value="ID ASC"),@Index(value="AGE DESC")}或者
    indexes={@Index(value="ID ASC AGE DESC")})))
    nameInDb   表示该实体对应的数据表的名称,默认为实体名的拼音全大写
    generateGettersSetters   表示是否自动生成get/set方法,默认为true
@Id   标识主键,该字段的类型为long或Long类型(推荐Long),autoincrement设置是否自动增长,默认为false
@Property   标识该属性在表中对应的列名称, nameInDb设置名称
@Transient   表示在创建数据表时候忽略这个字段,也就是在创建表的时候不会创建这个字段
@NotNull   设置表中当前列的值不可为空
@Convert   指定自定义类型(@linkPropertyConverter)
@Generated   greenDAO运行所产生的构造函数或者方法,被此标注的代码可以变更或者下次运行时清除
@Index   使用@Index作为一个属性来创建一个索引;定义多列索引(@link Entity#indexes())
@JoinEntity   定义表连接关系
@JoinProperty   定义名称和引用名称属性关系
@referencedJoinProperty   表示当前标识的实体对应的数据表的主键
@Keep   注解的代码段在GreenDao下次运行时保持不变
        1.注解实体类:默认禁止修改此类
        2.注解其他代码段,默认禁止修改注解的代码段
@OrderBy   指定排序
@ToMany   定义与多个实体对象的关系
@ToOne   定义与另一个实体(一个实体对象)的关系
@Unique   向数据库列添加了一个唯一的约束

5、generator构建

点击工具栏build下面的Make Project,对项目进行重新构建,在daoPackage的目录下就会自动生成相应的类(DaoMaster,DaoSession,FriendDao,UserDao),同时对应的实体类也发生改变。

generator构建结果图

Friend实体类变化后代码:User实体类也发生类似变化

/**
 * 朋友表+实体类
 * Created by 邹峰立 on 2017/9/23 0023.
 */
@Entity(
        // active表示update/delete/refresh 方法是否自动生成,默认为false
        active = true,
        // createInDb表示是否在数据库中创建该表,默认为true
        createInDb = true,
        // generateConstructors表示是否生成构造方法(一般有两个,一个有参数,一个无参数),默认为true
        generateConstructors = true,
        // indexes表示数据表查询返回数据默认排序,name中的字段是该实体在数据表中的列名,value表示改实体的真实名称,unique表示是否唯一(默认为false)
        indexes = {@Index(value = "_id ASC"),@Index(value = "fId DESC")},
        // nameInDb表示数据表的名称默认为实体类的名称
        nameInDb = "t_friend",
        // 表示是否生成get/set方法,默认为true
        generateGettersSetters = true
)
public class Friend {
    @Id(autoincrement = true)
    @Property(nameInDb = "_id")
    private long _id;
    @NotNull
    @Unique
    @Property(nameInDb = "f_id")
    private long fId;// ID
    @NotNull
    @Property(nameInDb = "f_gname")
    private String fGname;// 组名
    @NotNull
    @Property(nameInDb = "f_uid")
    private long fUid;// 用户ID

    @ToOne(joinProperty = "fUid")
    private User user;
    /** Used to resolve relations */
    @Generated(hash = 2040040024)
    private transient DaoSession daoSession;
    /** Used for active entity operations. */
    @Generated(hash = 76285035)
    private transient FriendDao myDao;
    @Generated(hash = 251390918)
    private transient Long user__resolvedKey;

    public Friend() {
        super();
    }

    public Friend(long fId, String fGname, long fUid) {
        this.fId = fId;
        this.fGname = fGname;
        this.fUid = fUid;
    }

    @Generated(hash = 1517071117)
    public Friend(long _id, long fId, @NotNull String fGname, long fUid) {
        this._id = _id;
        this.fId = fId;
        this.fGname = fGname;
        this.fUid = fUid;
    }

    public long getfId() {
        return fId;
    }

    public void setfId(long fId) {
        this.fId = fId;
    }

    public String getfGname() {
        return fGname;
    }

    public void setfGname(String fGname) {
        this.fGname = fGname;
    }

    public long getfUid() {
        return fUid;
    }

    public void setfUid(long fUid) {
        this.fUid = fUid;
    }

    @Override
    public String toString() {
        return "Friend{" +
                "fId=" + fId +
                ", fGname='" + fGname + '\'' +
                ", fUid=" + fUid +
                '}';
    }

    public long get_id() {
        return this._id;
    }

    public void set_id(long _id) {
        this._id = _id;
    }

    public long getFId() {
        return this.fId;
    }

    public void setFId(long fId) {
        this.fId = fId;
    }

    public String getFGname() {
        return this.fGname;
    }

    public void setFGname(String fGname) {
        this.fGname = fGname;
    }

    public long getFUid() {
        return this.fUid;
    }

    public void setFUid(long fUid) {
        this.fUid = fUid;
    }

    /** To-one relationship, resolved on first access. */
    @Generated(hash = 736394026)
    public User getUser() {
        long __key = this.fUid;
        if (user__resolvedKey == null || !user__resolvedKey.equals(__key)) {
            final DaoSession daoSession = this.daoSession;
            if (daoSession == null) {
                throw new DaoException("Entity is detached from DAO context");
            }
            UserDao targetDao = daoSession.getUserDao();
            User userNew = targetDao.load(__key);
            synchronized (this) {
                user = userNew;
                user__resolvedKey = __key;
            }
        }
        return user;
    }

    /** called by internal mechanisms, do not call yourself. */
    @Generated(hash = 113038422)
    public void setUser(@NotNull User user) {
        if (user == null) {
            throw new DaoException(
                    "To-one property 'fUid' has not-null constraint; cannot set to-one to null");
        }
        synchronized (this) {
            this.user = user;
            fUid = user.get_id();
            user__resolvedKey = fUid;
        }
    }

    /**
     * Convenient call for {@link org.greenrobot.greendao.AbstractDao#delete(Object)}.
     * Entity must attached to an entity context.
     */
    @Generated(hash = 128553479)
    public void delete() {
        if (myDao == null) {
            throw new DaoException("Entity is detached from DAO context");
        }
        myDao.delete(this);
    }

    /**
     * Convenient call for {@link org.greenrobot.greendao.AbstractDao#refresh(Object)}.
     * Entity must attached to an entity context.
     */
    @Generated(hash = 1942392019)
    public void refresh() {
        if (myDao == null) {
            throw new DaoException("Entity is detached from DAO context");
        }
        myDao.refresh(this);
    }

    /**
     * Convenient call for {@link org.greenrobot.greendao.AbstractDao#update(Object)}.
     * Entity must attached to an entity context.
     */
    @Generated(hash = 713229351)
    public void update() {
        if (myDao == null) {
            throw new DaoException("Entity is detached from DAO context");
        }
        myDao.update(this);
    }

    /** called by internal mechanisms, do not call yourself. */
    @Generated(hash = 1516049992)
    public void __setDaoSession(DaoSession daoSession) {
        this.daoSession = daoSession;
        myDao = daoSession != null ? daoSession.getFriendDao() : null;
    }
}

到这里greenDao的前期准备工作就算完成了,接下来就是对greenDao进行封装和使用。

6、定义DBHelper,让其继承DaoMaster.OpenHelper,并实现抽象方法,其中onUpgrade方法是用于实现数据库升级维护处理。

/**
 * OpenHelper
 * Created by 邹峰立 on 2017/9/23 0023.
 */
public class DBHelper extends DaoMaster.OpenHelper {
    public static final String DBNAME = "ibookerdata.db";

    public DBHelper(Context context, String name) {
        this(context, name, null);
    }

    public DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
        super(context, name, factory);
    }

    /**
     * 当数据库版本更新的时候回调函数
     *
     * @param db         数据库对象
     * @param oldVersion 数据库旧版本
     * @param newVersion 数据库新版本
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        super.onUpgrade(db, oldVersion, newVersion);
        if (newVersion > oldVersion) {
            // 创建临时表
            // 复制旧数据到临时表
            // 数据库(表)删除
            // 临时表重命名
        }
    }
}

7、创建greenDao管理类GreenDaoManager,在该类中实现对DaoMaster和DaoSession的管理。

/**
 * GreenDao管理类
 */
public class GreenDaoManager {
    private DaoMaster mDaoMaster;
    private DaoSession mDaoSession;
    private static volatile GreenDaoManager mInstance = null;

    // 构造方法
    private GreenDaoManager() {
        if (mInstance == null) {
            // 重写DBHelper数据库升级,数据不丢失
            // MyApplication.getContext()上下文表示了数据库存储路径为手机内存
            DBHelper helper = new DBHelper(MyApplication.getInstance(), DBHelper.DBNAME, null);
            mDaoMaster = new DaoMaster(helper.getWritableDatabase());
            mDaoSession = mDaoMaster.newSession();
        }
    }

    // 单例模式
    public static GreenDaoManager getInstance() {
        if (mInstance == null) {
            synchronized (GreenDaoManager.class) {
                if (mInstance == null) {
                    mInstance = new GreenDaoManager();
                }
            }
        }
        return mInstance;
    }

    public DaoMaster getMaster() {
        return mDaoMaster;
    }

    public DaoSession getSession() {
        return mDaoSession;
    }

    // 获取新的DaoSession
    public DaoSession getNewSession() {
        mDaoSession = mDaoMaster.newSession();
        return mDaoSession;
    }

    // 打印查询日志
    public static void enableQueryBuilderLog(){
        QueryBuilder.LOG_SQL = true;
        QueryBuilder.LOG_VALUES = true;
    }
}

同时自定义Application,实现GreenDaoManager初始化工作。

/**
 * 自定义MyApplication
 * Created by 邹峰立 on 2017/9/23 0023.
 */
public class MyApplication extends Application {
    private static MyApplication instance;

    @Override
    public void onCreate() {
        super.onCreate();
        // 全局上下文赋值
        instance = this;
        // 初始化数据库
        GreenDaoManager.getInstance();
    }

    // 获取全局上下文对象
    public static MyApplication getInstance() {
        return instance;
    }
}

注意:最后要在中进行引用

<application
        android:name="cc.ibooker.myapplition.MyApplication"
...
</application>

8、封装数据库表相应的管理类。

/**
 * 对数据库t_user进行管理
 * Created by 邹峰立 on 2017/9/23 0023.
 */
public class UserDbUtil {
    private static volatile UserDbUtil mInstance = null;
    private UserDao userDao;

    // 构造方法
    private UserDbUtil() {
        if (mInstance == null) {
            userDao = GreenDaoManager.getInstance().getSession().getUserDao();
        }
    }

    // 单例
    public static UserDbUtil getInstance() {
        if (mInstance == null) {
            synchronized (UserDbUtil.class) {
                if (mInstance == null) {
                    mInstance = new UserDbUtil();
                }
            }
        }
        return mInstance;
    }

    // 查询全部用户信息
    private List<User> queryAll() {
        List<User> users = userDao.queryBuilder().list();
        for (User user : users)
            Log.d("queryAll", user.toString());
        return users;
    }
    ...
}
/**
 * 朋友表t_friend进行管理
 * Created by 邹峰立 on 2017/9/23 0023.
 */
public class FriendDbUtil {
    private static volatile FriendDbUtil mInstance = null;
    private FriendDao friendDao;

    // 构造方法
    private FriendDbUtil() {
        if (mInstance == null) {
            friendDao = GreenDaoManager.getInstance().getSession().getFriendDao();
        }
    }

    // 单例
    public static FriendDbUtil getInstance() {
        if (mInstance == null) {
            synchronized (UserDbUtil.class) {
                if (mInstance == null) {
                    mInstance = new FriendDbUtil();
                }
            }
        }
        return mInstance;
    }
    ...
}

9、使用

这里只需要调用相应表的管理类就可以实现对表的增删改查。如:查询全部用户信息。

UserDbUtil userDbUtil = UserDbUtil.getInstance();
List<User> user = userDbUtil.queryAll();

GitHub地址
阅读原文


微信公众号:书客创作
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容