LitePal是Android《第一行代码》作者郭神的开源ORM框架,一个很好用的ORM。
虽然好用,但是如果不加注意,会遇到很多坑。所谓坑,并不是说框架不好,只是说有一些细节注意不到可能会犯错。
这不是bug,但是教程也好,示例demo中也罢,很少有提到,只能在使用过程中一一总结了。
以下总结自己使用中遇到的问题,逐步完善。
先介绍下简单使用:
app目录下的build.gradle中增加依赖:
//litepal数据库ORM implementation 'org.litepal.guolindev:core:3.2.3'
在assets文件夹下创建一个相应的litepal.xml文件夹::
<?xml version="1.0" encoding="utf-8"?> <litepal> <dbname value="testdb"/> <version value="1"/> <list> <mapping class="com.test.model.User"/> </list> <storage value="mydir" /> </litepal>
在Application的onCreate中,增加初始化:LitePal.initialize(this);引入完毕。
问题一:
默认的数据库存储位置问题,可在litepal.xml文件中指定storage value="external"或者 "internal",默认是internal,文件浏览器查看是不可见或无权限的。external则在Android/data/目录下能找到数据库文件。但是,无论设置为哪种,只要应用卸载,数据库就跟着清除掉了。
如何能够持久保留数据库文件,不受是否卸载的影响呢?也简单,改下storage即可。
如:storage value="mydir" ,就会在根目录下的mydir目录下找到数据库文件。但前提是这个mydir已经提前创建好吧,若未创建会怎样,试下就知道。
问题二:
多表关联问题,关联的表无法存入数据。
这里有个隐藏的秘密,很难发现。建立一对一关联或一对多关联后,首先你要记得把关联表的数据save!!并不是你直接把数据set赋值之后,关联表就有数据了。set只是给两个表建立关联的。并且,除了save外,那个set也一样不能漏,否则你会看到关联的表里那个外键字段内容为空。
正解如:
News news=new News(); news.setTitle("这是一条新闻标题"); news.setContent("这是一条新闻内容"); news.setPublishDate(new Date()); Introduction introduction=new Introduction(); introduction.setGuide("这是新闻导语"); introduction.setDigest("这是新闻摘要"); news.setIntroduction(introduction);//只是建立关联 introduction.save();//重点 news.save();
问题三:
有多表关联的实体,查询时查出来的关联的表内容为空。
比如定义了一个实体,内部还关联了其他实体类。查询时如果不加注意,只能查到本实体的内容,关联的实体查到的为空。
举例如:
public class OrderDishTransdtlRecord extends LitePalSupport { @Column(nullable = false) private String billno;// 点餐单号 @Nullable private String goodsid;//菜品编号 char(16) @Nullable private String typename; //菜品类别名称 private int orderno;// 每笔订单菜品序列号 private int price; private int qty; @Column(ignore = true) private List<OrderComboFoodRecord> comboFoods;// 套餐详情,不存数据库 private List<OrderDishTransdtlRecord> dtlList;// 细节 关联OrderDishDtlRecord ..... }
如果只是想当然的 LitePal.find(OrderTransdtlRecord.class,10),这样查到的dtlList为null,没有数据。而应该如下写法:
OrderTransdtlRecord recc = LitePal.find(OrderTransdtlRecord.class,10,true);//重点,第三个参数必须有,且为true Log.d(TAG,recc.toString());
问题四:
删除一条记录,关联的表里内容本该跟着删除的,但是数据还在,删除不掉的问题。如:
OrderTransdtlRecord recc = LitePal.find(OrderTransdtlRecord.class,10); recc.delete();
这样是删不掉OrderTransdtlRecord的关联表OrderDishTransdtlRecord中的数据的。原因跟上个类似,这里的查询没增加第三个参数,isEager:True to load the associated models, false not.加上第三个参数,查询成功后,再删除,这样关联表才会跟着删除。或者使用这种方式,LitePal.delete(OrderTransdtlRecord.class,18),关联表会跟着删除。
或者使用这种方式,关联的表也会随之删除:
LitePal.deleteAll(OrderTransdtlRecord.class,"id = ? ","19");
问题五:
LitePal中不支持枚举类型。如果你的model里使用了枚举类型,在生成的表结构里枚举类型的字段会被忽略。
常用的类型如String和int,long可以放心用,其他类型需做好测试,不能想当然。
LitePal支持的数据类型有8种,分别为:int、short、long、float、double、boolean、String和Date。其他不支持的如枚举,会被忽略。
并且,如果里面使用了表关联,需在litpal.xml中注册,否则,也会被忽略,而非生成关联的表结构。
在进行boolean类型操作的时候也需要注意。对于LitePal数据库,存储boolean值为true的时候可以直接用LitePal存储对象的方式存储,若存储的对象中boolean为false,需要调用setToDefault(String name)方法存储,其中参数name为对象中Boolean属性的名称,为字符串boolean值其实是以0和1的方式存到数据库中的,true=1,false=0,所以在查询的时候需要注意。
问题六:
LitePal数据库的操作,默认是在主线程中的,使用时需注意自己处理线程和异步问题。
虽然之前版本LitePal提供的有异步操作api,但是作者说了,尽量少用。后续版本可能废弃不再维护。推荐应用开发者自己处理异步问题,如使用RxJava异步库。
问题七:
LitePal不能更改数据库表名和字段名。默认的表名就是定义的实体类的类名,且都为小写,字段名都是实体类中定义的属性的小写。
问题八:
LitePal不支持自定义主键,默认的主键为id,不管一个实体类对象有没有设置id字段,数据库的表中都会创建一个id的主键,而这个id的值会在新记录插入时被自动置为表中的Id,也即是唯一值。如果你里面定义了个String id,运行会报错的。
问题九:
升级表结构时要格外注意,以防历史数据被清空。以下一些升级情况LitePal无法处理并且被升级表格里的所有数据将被清空:
添加了一个标注为 unique = true 的属性;
修改某个属性的标注为 unique = true;
修改某个属性的标注为 nullable = false;
以上情况会导致数据丢失,要格外注意。