GreenDao增删改查使用中的一些坑

入坑前的铺垫

昨天在上一篇[GreenDao项目接入]http://www.jianshu.com/p/dac3bd9bad72 中说明了在项目中使用GreenDao的一个流程,因为时间问题没有详细的讲解有关增删改查的一些问题,今天给大家补充一下。

public class User extends BaseBean
{
    private int memberSex;//性别
    private String memberLastX;//X币
    private String memberNickname;//昵称
    private String memberIcon;//头像地址链接
    private String memberMobile;//手机号
    private int memberId;//用户ID
    private String memberDetailAddr;//用户的详细地址
    private String memberLastExperience;//用户经验值
    private String memberLevelName;//用户等级昵称
    private long memberBirthday;//用户生日
    private String memberProvince;//用户所在地
}

上面为我实际开发中用来获取接口用户信息的实体类,然后我按照步骤对实体类进行了注释,如下:

@Entity
public class User extends BaseBean
{
    @Id
    private Long id;
    private int memberSex;//性别
    private String memberLastX;//X币
    private String memberNickname;//昵称
    private String memberIcon;//头像地址链接
    private String memberMobile;//手机号
    private int memberId;//用户ID
    private String memberDetailAddr;//用户的详细地址
    private String memberLastExperience;//用户经验值
    private String memberLevelName;//用户等级昵称
    private long memberBirthday;//用户生日
    private String memberProvince;//用户所在地
}

不知道大家有没有仔细观察,我在实体类里面又定义了一个Long类型的字段作为ID(是按照官方Demo中开发的),正是这个ID,让我掉了一次坑,给大家详细的描述下当时我遇到的问题以及解决办法:

我按照上面的实体类去Make project生成对应的UserDao和DaoMaster、DaoSession。然后我在代码里面缓存用户信息的时候是这么做的,首先从服务器获取用户数据,然后转换成一个User对象使用GreenDao进行本地缓存,代码如下:

/**
     * 缓存用户信息
     *
     * @param user
     */
    public void cacheUserInfo(User user)
    {
        UserDao userDao = GreenDaoManager.getInstance().getmDaoSession().getUserDao();
        userDao.save(user);
    }

GreenDao里面提供存储数据的方法有三个:

  • save(T entity)
    "Saves" an entity to the database: depending on the existence of the key property, it will be inserted (key is null) or updated (key is not null).通过key属性判断是否存在,如果存在就更新数据,如果key为null就插入。这里的key是什么东东?这就是我今天被坑的地方,这个key就是我新增的Long id这个字段,也就是表中的主键
  • insert(T entity)
    Insert an entity into the table associated with a concrete DAO.
    插入实体类,这个是直接插入。
  • insertOrReplace(T entity)
    Insert an entity into the table associated with a concrete DAO.将实体插入到与具体DAO关联的表中,这是官方api的给的解释,不过他的实际效果和svae很类似,就是如果存在就修改,不存在插入。

这里先说一下查询的方法吧,官方提供查询的方法有:

  • loadByRowId(long rowId)
  • load(K key)
    Loads the entity for the given PK.
    根据主键获取对象,也就是通过id获取

但是我只有实体类的memberId,也就是在服务器上生成的Id,所以肯定没法用这两个方法获取到数据,然后又查文档,发现[QueryBuilder<T>]http://greenrobot.org/files/greendao/javadoc/current/ ,在QueryBuilder中提供了几个方法:

  • unique()
    Shorthand for build()
    .
    Shorthand for build()
    .unique()
    ; see Query.unique()
    for details. To execute a query more than once, you should build the query and keep the Query
    object for efficiency reasons.
    大概的意思就是说通过build对象构建一个Query<T>的对象,可以重复反复的利用这个去进行获取数据

入坑ing

我是怎么入坑的? 当时我看了文档之后发现save挺智能的嘛,就寻思着用save吧,自身就是在插入前做个判断,省时省力,然后就有了上面的那段代码,然后我在就在个人中心去获取缓存的数据,方法如下:

 /**
     * 从本地缓存中获取user对象
     *
     * @param memberId 用户ID
     * @return 返回用户信息
     */
    public User getUserInfoFromCache(String memberId)
    {
        UserDao userDao = GreenDaoManager.getInstance().getmDaoSession().getUserDao();
        Query<User> query = userDao.queryBuilder().where(UserDao.Properties.MemberId.eq(memberId))
                                   .orderDesc(UserDao.Properties.MemberId).build();
        return query.unique();
    }

看起来没有什么问题,然后我就去跑程序测试,第一次发现吆喝,果然好使,执行完后数据库果然有了一行数据,屁颠的退出再来一遍,竟然崩了,一看日志提示:Expected unique result, but count was 2,意思就是说unique只能查询数据库中有一条符合条件的数据,上面的方法中我的查询条件是.where(UserDao.Properties.MemberId.eq(memberId)),也就是memberId等于当前用户的,打印输出果然数据库有两条数据,然后找原因,肯定是在缓存的方法中去找,发现save也没什么问题啊,想不通的时候必杀绝招就是看源码

出坑

save的源码如下:

  public void save(T entity) {
        if (hasKey(entity)) {
            update(entity);
        } else {
            insert(entity);
        }
    }

大家可以看到其实他就是update和insert的一个判断使用,有个hasKey的方法,然后查看hasKey的源码:

abstract protected boolean hasKey(T entity);

发现是一个抽象方法,那我只能去他的继承类UserDao里面去找了

@Override
public boolean hasKey(User entity)
 {   
     return entity.getId() != null;
 }

终于找到了真凶,没错 ,就是我们定义的Long id这个字段,原来他在插入之前是判断了这个是否存在,如果不存在就执行插入,如果存在就更新,然后就明白了,我在插入数据的时候是从服务器获取到的数据,只有memberId,而没有本地数据库的id,所以第二次缓存的时候仍然是执行了insert的操作,然后在查询的时候肯定出现了问题,真相大白就可以想办法解决了。下面是我的解决代码:

  /**
     * 缓存用户信息
     *
     * @param user
     */
    public void cacheUserInfo(User user)
    {
        User oldUser = getUserInfoFromCache(user.getMemberId() + "");
        if (oldUser != null)
        {
            user.setId(oldUser.getId());
        }
        UserDao userDao = GreenDaoManager.getInstance().getmDaoSession().getUserDao();
        userDao.save(user);
    }

在插入之前坐了个判断,判断是否有memberId相同的存在,如果存在取出GreenDao对应的id,放入user,这样在hasKey判断的时候肯定是执行update了。ok,问题解决。不过,还有一种可能,说可不可能不添加Long id这个字段,直接给我们的memberId添加@Id呢,实际上试试不行的。大家看下面修改之后的代码就知道了:

@Entity
public class User extends BaseBean
{
    private int memberSex;//性别
    private String memberLastX;//X币
    private String memberNickname;//昵称
    private String memberIcon;//头像地址链接
    private String memberMobile;//手机号
    @Id
    private int memberId;//用户ID
    private String memberDetailAddr;//用户的详细地址
    private String memberLastExperience;//用户经验值
    private String memberLevelName;//用户等级昵称
    private long memberBirthday;//用户生日
    private String memberProvince;//用户所在地
}

然后Make project,执行了下出现问题了,然后去查看hasKey的代码:

 @Override
    public boolean hasKey(User entity) {
        throw new UnsupportedOperationException("Unsupported for entities with a non-null key");
    }

变成了直接抛出异常了,所以,这个想法大家就别想了,如果有更好的办法欢迎大家下方留言告知。谢谢。
我每天都会更新一个小知识给大家,如果有兴趣可以关注,指不定什么时候就可以帮到你了,谢谢大家。

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

推荐阅读更多精彩内容