LitePal是一款开源的Android数据库框架,采用了ORM对象关系映射的模式,将常用的数据库功能进行了封装。是大名鼎鼎郭神的杰作。
下面我主要分三重境界来讲解:咋用?咋关联?咋增删改查?适合各个层次的人用来进一步更深入地了解和应用LitePal,下面开始正题…
第一重境界:LitePal咋用????
第一重境界一定要认真阅读郭神的《Android数据库高手秘籍》,上下共八篇,下面是第零篇的链接
http://blog.csdn.net/sinyu890807/article/details/38083103,让我们一起来好生阅读,然后再来读本文的总结,就有望早日突破三界之外…
1.在AndroidStudio中的moudle的buildgradle中添加依赖:
dependencies {
compile 'org.litepal.android:core:1.3.2'
}
2.在Project目录结构的main下建立assets文件夹,并在assets下创建litepal.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<dbname value="demo"></dbname>
<version value="1"></version>
<list>
</list>
</litepal>
3.在清单文件中加入LitePalApplication的申明:
<manifest>
<application
name="org.litepal.LitePalApplication"
...
>
...
</application>
</manifest>
注:1),如果用到了自定义的Application,只需要将自定义的Application继承LitePalApplication。
2),如果必须要继承第三方Jar包里的Application,可以将litePal的源码下载然后添加到项目中,然后修改LitePalApplication继承第三方Jar包的Application,然后自定义的Application再继承LitePalApplication就OK了。
4.根据对象关系映射模式的概念,每一张表应该对应一个模型,比如说要建一张新闻类的News表,可以这样:
public class News extends DataSupport{//继承关系不可少
private int id; // 可以不写,LitePalace会自定生成
private String title;
private String content;
private Date publishDate;
private int commentCount;
// getter、setter
}
注:1).映射的数据类型一共有8种:int、short、long、float、double、boolean、String和Date ;
2).使用LitePal只有声明private的字段才会被映射到数据表中,如果不想映射的话,修饰符设置为public、protected、default就可以了。
3).必须要继承DataSupport,不能忘 。
5.在litepal.xml文件中加入模型类的申明:
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<dbname value="demo"></dbname>
<version value="1"></version>
<list>
<mapping class="com.example.databasetest.model.News"/>
</list>
</litepal>
6.在入口Activity或者自定义的Application的onCreate()方法中获取SQLiteDatabase的实例,就可以执行建表逻辑了,如下:
SQLiteDatabase db = Connector.getDatabase();
7.使用LitePal升级表的时候,比如说加减列,增删表,都可以通过操作Model来间接操作表,然后在 litepal.xml 中的增加数据库的版本就好了:
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<dbname value="demo"></dbname>
<version value="1"></version>
<list>
<mapping class="com.example.databasetest.model.News"/>
<mapping class="com.example.databasetest.model.Comment"/>
</list>
</litepal>
第二重境界:LitePal咋建关联表?????
个人理解:LitePal其实是用model来映射表,只需要考虑model与model的关联关系,litepal会由此自动生成表的关联关系,不用我们考虑表的关关联。
下面就来将郭神在八篇数据库里面的四张表(),堆在这里来说明一对一,多对一,多对多三种关联表,重点是多对一的情况。
首先是新闻类News,对应News表:
public class News extends DataSupport{
private int id;
private String title;
private String content;
private int commentCount;
private Date publishDate;
//News和Introdection是一对一的关系:1/1步到位
private Interduction interduction;
//News和Comment是多对一的关系:1/2步
private List<Comment> commentList=new ArrayList<>();
//News和Category是多对多的关系:1/2步
private List<Category> categoryList=new ArrayList<>();
//自动生成getter,setter方法
}
然后是简介表Introdection,对应Introdection表,它和News是一对一的关系:
public class Interduction extends DataSupport{
private int id;
private String guide;
private String digest;
//private News news;//这里和News表中的Introdection对象,二选一保留均可
//自动生成getter,setter方法
}
接下来是Comment,对应的是Comment表,它和News是多对一的关系:
public class Comment extends DataSupport{
private int id;
private String content;
private Date publishDate;
//Comment和News是多对一的关系:2/2步
private News news;
//自动生成getter,setter方法
}
最后是类别类Category,对应Category表,它和News是多对多的关系:
public class Category extends DataSupport{
private int id;
private String name;
//News和Category是多对多的关系:2/2步
private List<News> newsList=new ArrayList<>();
//自动生成getter,setter方法
}
如此四个model,既有各model之间的关系又在内部暗含四张表的关联关系。这样写十分便宜,如果读者看不明白,真心希望读者去看郭神自己的介绍。。。
第三重境界:LitePal的增删改查
1.增加数据:
private void saveNews(){
News news = new News();
news.setTitle("这是一条新闻标题");
news.setContent("这是一条新闻内容");
news.setPublishDate(new Date());
Log.d("TAG", "news id is " + news.getId());//输出是0,id字段此时还没有赋值
if (news.save()) {
Log.d("TAG", "news id is " + news.getId());//输出是1,id字段此时才赋值:数据库第一条数据的主键id是从1开始的
Toast.makeText(this, "存储成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "存储失败", Toast.LENGTH_SHORT).show();
}
//或者可以使用当 save()方法返回false时能抛出异常的saveThrows();
}
2.增加数据集合:
private void saveList(){
List<News> newsList=new ArrayList<>();
//...
//传统的存储方式:一个一个存
//for (News news : newsList) {
// news.save();
//}
//LitePal存储方式:直接存集合
DataSupport.saveAll(newsList);
}
3.关联表存储,eg:多对一存储。
private void saveMutiToOne(){
Comment comment = new Comment();
comment.setContent("好评!");
comment.setPublishDate(new Date());
// 1/3步:先将comment存储到Comment表
comment.save();
Comment comment2 = new Comment();
comment2.setContent("赞一个");
comment2.setPublishDate(new Date());
comment2.save();
News news = new News();
// 2/3步:通过下面的方法将comment和news数据经行多对一关联:外键关联在这里设置
news.getCommentList().add(comment);
news.getCommentList().add(comment2);
news.setTitle("第二条新闻标题");
news.setContent("第二条新闻内容");
news.setPublishDate(new Date());
news.setCommentCount(news.getCommentList().size());
// 3/3步:将news对象存储到News表中:外键在这里成功关联
news.save();
}
注 :1). 内行的朋友肯定会知道多对一是通过外键经行存储的,但是这里我们并没有指定任何外键,原因大概是:LitePal的外键是托管的或者说是自动设置的,这个时候当调用news的save方法时,LitePal会为该条news添加正确的id,然后会将此id自动存放到两个comment对应的外键列上,从而完成了通过外键经行数据的关联。
2). 口诀:一对一 ,多对一,通过外键关联,多对多通过中间表关联
3). 我们不需要考虑在存储数据的时候怎么去建立数据与数据之间的关联,因为LitePal一切都帮我们做好了。而多对多或者是一对一也是同理。
4.修改数据:
private void updateData(){
//一/,使用ContentValues经行数据的修改
//1/修改指定某行某列的数据
ContentValues values = new ContentValues();
values.put("title", "今日iPhone6发布");
DataSupport.update(News.class, values, 2);
//2/根据限定条件修改多行的某列数据
ContentValues values1 = new ContentValues();
values1.put("title", "今日iPhone6发布");
DataSupport.updateAll(News.class, values1, "title = ?", "今日iPhone16发布");
//3/当多个限定条件时该这样写
DataSupport.updateAll(News.class, values, "title = ? and commentcount > ?", "今日iPhone6发布", "0");
//4/当没有约束条件修改表中所有行的某列数据
DataSupport.updateAll(News.class, values);
//二/如果不想使用ContentValues可以使用Model对象
//1/修改指定某行某列的数据:
News updateNews = new News();
updateNews.setTitle("今日iPhone6发布");
updateNews.update(2);
//2/当多个限定条件修改多行的某列数据时该这样写
News updateNews2 = new News();
updateNews2.setTitle("今日iPhone6发布");
updateNews2.updateAll("title = ? and commentcount > ?", "今日iPhone6发布", "0");
//3/当将所有行某列的数据设置成默认值时:只能用下面的方法
News updateNews3 = new News();
updateNews3.setToDefault("commentCount");
updateNews3.updateAll();
}
- 删除数据:与修改数据相似
private void deleteData(){
//1/删除某行数据:会一同删除与此条数据有外键关系的所有数据
DataSupport.delete(News.class, 2);//该方法返回int类型:一共删除了多少条数据
//2/指定条件删除多行数据
DataSupport.deleteAll(News.class, "title = ? and commentcount = ?", "今日iPhone6发布", "0");
//3/删除表中所有数据
DataSupport.deleteAll(News.class);
//4/删除已经储存的数据
News news = new News();
news.setTitle("这是一条新闻标题");
news.setContent("这是一条新闻内容");
news.save();
//...
news.delete();
//5/判断一条数据是否持久化(存储过)
if (news.isSaved()) {
news.delete();
}
}
6.查询数据:
private void queryData(){
//1/查询指定行的数据
News news = DataSupport.find(News.class, 1);
//2/查询第一行或最后一行的数据
News firstNews = DataSupport.findFirst(News.class);
News lastNews = DataSupport.findLast(News.class);
//3/查询指定多行数据
List<News> newsList = DataSupport.findAll(News.class, 1, 3, 5, 7);
//4/查询行号组成的数组里面的多行数据
long[] ids = new long[] { 1, 3, 5, 7 };
List<News> newsList2 = DataSupport.findAll(News.class, ids);
//5/查询某表所有行的数据
List<News> allNews = DataSupport.findAll(News.class);
//6/根据某列的约束条件经行查询
List<News> newsList3 = DataSupport.where("commentcount > ?", "0").find(News.class);
//7/根据返回集合多列需求经行约束条件查询(如下:只需要title和content两列数据)
List<News> newsList4 = DataSupport.select("title", "content")
.where("commentcount > ?", "0").find(News.class);
//8/根据返回集合排序需求经行约束条件查询(如下:根据发布时间倒序排序)asc表示正序排序,desc表示倒序排序
List<News> newsList5 = DataSupport.select("title", "content")
.where("commentcount > ?", "0")
.order("publishdate desc").find(News.class);
//9/根据返回集合限制数量需求经行约束条件查询
List<News> newsList6= DataSupport.select("title", "content")
.where("commentcount > ?", "0")
.order("publishdate desc").limit(10).find(News.class);
//10/根据返回集合指定起始需求经行约束条件查询
List<News> newsList7 = DataSupport.select("title", "content")//指定列
.where("commentcount > ?", "0")//约束条件
.order("publishdate desc")//正序排列
.limit(10)//共需要10条数据
.offset(10)//第10条数据开始
.find(News.class);//指定表
//11/连带关联表中的数据进行激进查询
News news0 = DataSupport.find(News.class, 1, true);
List<Comment> commentList = news.getCommentList();
//12/查询时不推荐使用激进查询,如果确实需要可以在Model表中添加这样的方法
// public class News extends DataSupport{
//
// ...
//
// public List<Comment> getComments() {
// return DataSupport.where("news_id = ?", String.valueOf(id)).find(Comment.class);
// }
//
// }
}
7.聚合函数:
private void togetherMeath(){
//1/count()方法就是用于统计行数
int result = DataSupport.count(News.class);
//2/约束条件统计行数
int result1 = DataSupport.where("commentcount = ?", "0").count(News.class);
//3/sum()方法主要是用于对结果进行求和的(限:整型,浮点型可用,其他类型(如字符串)不可用放回0)
int result2 = DataSupport.sum(News.class, "commentcount", int.class);
//4/max()方法主要是求出某个列的最大的数值(限:整型,浮点型可用)
int result3 = DataSupport.max(News.class, "commentcount", int.class);
//5/max()方法主要是求出某个列的最大的数值(限:整型,浮点型可用)
int result4= DataSupport.min(News.class, "commentcount", int.class);
}
附录:查询,修改boolean值得相关问题:
1).查询boolean类型的列:boolean在赋值都是true或false,但是实际存储时,存在数据库的为1或0,所以查询时查询参数应该为1和0,而不是true和false。
// 错误的写法
// List<Phone> noPowerPhones = DataSupport.where("power = ?", “false”).find(Phone.class);
// 正确的写法
List<Phone> noPowerPhones = DataSupport.where("power = ?", “0”).find(Phone.class);
2).修改boolean类型默认:boolean类型的字段在设置为真时就是是赋值true,以及使用setToDefault()方法
News updateNews = new News();
updateNews.setToDefault("isRead");
updateNews.updateAll();
自己拿个镜子照照自己,自己修炼到几重境界了。。。