Android 使用LitePal操作数据库

1.LitePal简介
LitePal是一款开源的Android数据库框架,它采用了对象关系映射(ORM)的模式,并将我们平时开发最常用到的一些数据库功能进行了封装,使得不用编写一行SQL语句就可以完成各种建表和增删改查的操作,LitePal的项目主页上也有详细的使用文档,地址是:http://github.com/LitePalFramework/LitePal
2.配置LitePal
要使用LitePal,第一步就是编辑app/build.gradle文件,在dependencies闭包中添加如下内容:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:25.3.1'
    testCompile 'junit:junit:4.12'
    compile 'org.litepal.android:core:1.3.2'
}

添加的这一行声明中,前面的部分是固定的,最后的1.3.2是版本号的意思,最新的版本号可以到LitePal的项目主页上去查看
这样我们就把LitePal成功引入到当前的项目中了,然后配置litepal.xml文件,右击app/src/main目录–New–Directory,创建一个assets目录,然后在assets目录下再新建一个litepal.xml文件,然后编辑


<litepal>
    <dbname value="BookStore" >dbname>

    <version value="1" >version>
    <list>
    list>
litepal>

其中dbname标签用于指定数据库名,version标签用于指定数据库版本号,list标签用于指定所有的映射模型

最后还需要在配置一下LitePalApplication,修改AndroidManifest.xml中的代码

"http://schemas.android.com/apk/res/android"
    package="com.example.litepaltest">
"org.litepal.LitePalApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        ...
    

这里将项目的application配置为org.litepal.LitePalApplication,这样才能让LitePal的所有功能都可以正常工作.
现在LitePal的配置工作已经全部结束,下面就是如何使用
3.创建和升级数据库
LitePal采用的是对象关系映射(ORM)的模式,那么什么是关系映射,简单的说,我们使用的编程语言是面向对象语言,而使用的数据库则是关系型数据库,那么将面向对象的语言和面向关系的数据库之间建立一种映射关系,这就是对象关系映射了.
对象关系映射模式,就是可以用面向对象的思维来操作数据库,而不用再和SQL语句打交道,比如,为了创建一张Book表,需要先分析表中应该包含那些列,然后再编写出一条建表语句,最后在自定义SQLiteOpenHelper中执行这条建表语句,但是使用LitePal,你就可以用面向对象的思维来实现同样的功能,定义一个Book类,代码如下:

public class Book {
    private int id;
    private String author;
    private double price;
    private int pages;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public int getPages() {
        return pages;
    }

    public void setPages(int pages) {
        this.pages = pages;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

这是一个典型的Java bean,在Book类中我们定义了id,author,price,pages,name这几个字段,并生成了相应的getter和setter方法,Book类就会对应数据库中的Book表,而类中的每一个字段分别对应了表中的每一个列,这就是对象关系映射最直接的体验
接下来我们还需要把Book类添加到映射模型列表当中,修改litepal.xml中的代码


<litepal>
    <dbname value="BookStore" >dbname>

    <version value="1" >version>
    <list>
        <mapping class="com.example.litepaltest.Book">mapping>
    list>
litepal>

这里使用mapping标签来声明我们要配置的映射模型类,注意一定要使用完整的类名.不管有多少模型类需要映射,都使用同样的方式配置在list标签下

修改MainActivity代码

public class MainActivity extends AppCompatActivity{
    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button createDatabase = (Button)findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Connector.getDatabase();
            }
        });
    }
}

其中,调用Connector.getDatabase()方法就是一次简单的数据库操作,只要点击一下按钮,数据库就会自动创建完成.

使用SQLiteOpenHelper来升级数据库,有一个问题就是升级数据库的时候我们需要先把之前的表drop掉,然后再重新创建才行,这其实是一个非常严重的问题,因为这样会造成数据丢失,每当升级一次数据库,之前表中的数据就全没了.当使用LitePal时,这些都不再是问题了.使用LitePal来升级数据库非常非常简单,你完全不用考虑任何的逻辑,只需要改你想改的内容,然后版本号加1就可以了

比如我们想要向Book表中添加一个press(出版社)列,直接修改Book类中的代码,添加一个press字段

public class Book {
    ...
    private String press;
    ...

    public String getPress() {
        return press;
    }

    public void setPress(String press) {
        this.press = press;
    }
}

于此同时,我们还想再添加一张Category表,那么只需要新建一个Category类就可以了

public class Category {
    private int id;
    private String categoryName;
    private int categoryCode;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getCategoryName() {
        return categoryName;
    }

    public void setCategoryName(String categoryName) {
        this.categoryName = categoryName;
    }

    public int getCategoryCode() {
        return categoryCode;
    }

    public void setCategoryCode(int categoryCode) {
        this.categoryCode = categoryCode;
    }
}

改完了所有我们想改的东西,只需要记得将版本号加1就行了.这里添加一个新的模型类,因此也需要将它添加到映射模型列表中.修改litepal.xml中的代码



<litepal>
    <dbname value="BookStore" >dbname>

    <version value="2" >version>
    <list>
        <mapping class="com.example.litepaltest.Book">mapping>
        <mapping class="com.example.litepaltest.Category">mapping>
    list>
litepal>

4.使用LitePal添加数据
使用LitePal添加数据,只需要创建出模型类的实例,然后将所有的要存储的数据设置好,最后调用一下save()方法就可以了
模型类必须继承DataSupport类,修改Book类

public class Book extends DataSupport{
    ...
}

修改MainActivity代码

public class MainActivity extends AppCompatActivity{
    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
        Button addData = (Button)findViewById(R.id.add_data);
        addData.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Book book = new Book();
                book.setName("The Da Vinci Code");
                book.setAuthor("Dan Brown");
                book.setPages(454);
                book.setPrice(16.96);
                book.setPress("Unknow");
                book.save();
            }
        });
    }
}

在添加数据按钮的点击事件里面,首先是创建出了一个Book实例.然后调用Book类中的各种set方法对数据进行设置,最后调用book.save()方法就能完成数据添加操作.这个save()方法是从DataSupport类中继承来的.除了save()方法,还有一些其他方法.
5.使用LitePal更新数据
首先,最简单的一种更新方式就是对已存储的对象重新设值,然后 重新调用save()方法.什么是已存储的对象,对于LitePal来说,对象是否已存储就是根据调用model.isSaved()方法的结果来判断的,返回true就表示已存储,返回false就表示未存储.实际上只有两种情况下model.isSaved()方法才会返回true,一种情况是已经调用过model.save()方法去添加数据,此时model会被认为是已存储的对象,另一种情况是model对象是通过LitePal提供的查询API查出来的,由于是从数据库中查到的对象,因此也会被认为是已存储的对象.
第一种情况的代码,修改MainActivity代码

public class MainActivity extends AppCompatActivity{
    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
        Button updateData = (Button)findViewById(R.id.update_data);
        updateData.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Book book = new Book();
                book.setName("The Lost Symbol");
                book.setAuthor("Dan Brown");
                book.setPages(510);
                book.setPrice(19.95);
                book.setPress("Unknow");
                book.save();
                book.setPrice("10.99");
                book.save();
            }
        });
    }
}

在更新数据按钮的点击事件里面,首先添加一条Book数据,然后调用setPrice()方法将这本书的价格进行修改,之后再调用了save()方法.此时LitePal会发现当前的Book对象是已存储的,因此不会再向数据库中去添加一条新的数据,而是会直接更新当前的数据.
另外一种更新方法,修改MainActivity代码

public class MainActivity extends AppCompatActivity{
    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
        Button updateData = (Button)findViewById(R.id.update_data);
        updateData.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Book book = new Book();
                book.setPrice(14.95);
                book.setPress("Anchor");
                book.updateAll("name = ? and author = ?","The Lost Symbol","Dan Brown");
            }
        });
    }
}

这里首先new一个Book实例,然后直接调用setPrice()方法和setPress()方法来设置要更新的数据,最后再调用updateAll()方法去执行更新操作.
注意:updateAll()方法中可以指定一个约束条件,和SQLiteDatabase中的update()方法的where参数部分有点类似,如果不指定条件约束的话,就表示更新所有数据.

注意:在使用updateAll()方法时,当你想把一个字段的值更新成默认值时,是不可以使用上面的方式来set数据的,在java中任何一种数据类型的字段都有一个默认值,例如int类型的默认值为0,boolean类型的默认值为false,String类型的默认值为null,因此,如果当new出一个Book对象时,其实所有字段都已经被初始化为默认值.比如说pages字段的值为0,因此,想把数据表中的pages更新为0,直接调用book.setPages(0)是不可以的,因为即使不调用这段代码,pages字段本身也是0,LitePal不会对这个列进行更新,对于所有想要将为数据更新成默认值的操作,LitePal提供了一个setToDefault()方法,然后传入相应的列名就可以了实现了.例如:

Book book = new Book();
book.setToDefault("pages);
book.updateAll();

6.使用LitePal删除数据
有两种方式,第一种比较简单,就是直接调用已存储对象的delete()方法就可以了.调用过save()方法的对象,或是通过LitePal提供的查询API查出来的对象,都是可以直接使用delete()方式来删除数据的.
另一种删除方式的代码如下:
修改MainActivity代码:

public class MainActivity extends AppCompatActivity{
    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
        Button deleteButton = (Button)findViewById(R.id.delete_data);
        deleteButton.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                DataSupport.deleteAll(Book.class,"price < ?","15");
            }
        });
    }
}

这里调用DataSupport.deleteAll()方法来删除数据,其中deleteAll()方法的第一个参数用于指定删除哪张表中的数据,Book.class表示删除Book表中的数据,后面的参数用于指定约束条件,这里的代码表示,删除Book表中的价格低于15的书.
deleteAll()方法不指定约束条件,就是要删除表中的所有数据
7.使用LitePal查询数据
LitePal查询表中的所有数据:

List books = DataSuppport.findAll(Book.class);

findAll()方法返回一个Book类型的List集合,我们不用像之前那样通过Cursor对象一行行去取值,LitePal已经自动帮助我们完成了赋值操作.
修改MainActivity代码:

public class MainActivity extends AppCompatActivity{
    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
        Button queryButton = (Button)findViewById(R.id.query_data);
        queryButton.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                List books = DataSuppport.findAll(Book.class);
                for(Book book:books){
                    Log.d("MainActivity", "book name is " + book.getName());
                    Log.d("MainActivity", "book author is " + book.getAuthor());
                    Log.d("MainActivity", "book pages is " + book.getPages());
                    Log.d("MainActivity", "book price is " + book.getPrice());
                    Log.d("MainActivity", "book press is " + book.getPress());
                }
            }
        });
    }
}

查询Book表中的第一条数据可以这样写:

Book firstBook = DataSuppport.findFirst(Book.class);

查询Book表中的最后一条数据可以这样写

Book lastBook = DataSuppport.findLast(Book.class);

我们可以通过连缀查询来定制更多的查询功能
select()方法用于指定查询那几列的数据,对应了SQL当中的select关键字,比如只查询name和author这两列的数据

List books = DataSuppport.select("name", "author").find(Book.class);

where()方法用于指定查询的约束条件,对应了SQL当中的关键字where,比如只查询页数大于400的数据,

List books = DataSuppport.where("pages > ?", "400").find(Book.class);

order()方法用于指定结果的排序方式,对应了SQL当中的order by 关键字,比如将查询结果按照书价格从高到低排序
desc表示降序排列,asc或者不写表示升序排列

List books = DataSuppport.order("price desc").find(Book.class);

limit()方法用于指定查询结果的数量,比如只查询表中的前3条数据

List books = DataSuppport.limit(3).find(Book.class);

offset()方法用于指定查询结果的偏移量,比如查询表中的第2条,第3条,第4条数据

List books = DataSuppport.limit(3).offset(1).find(Book.class);

还可以对这5个方法进行任意组合的连缀,来完成一个比较复杂的查询操作
查询Book表中第11–20条满足页数大于400这个条件的name,author和pages这3列数据,并将查询结果按照页数升序排列

List books = DataSuppport.select("name", "author", "pages")
                   .where("pages > ?", "400")
                   .order("pages")
                   .limit(20)
                   .offset(10)
                   .find(Book.class);

LitePal也支持使用原生的SQL来查询:

Cursor c = DataSupport.findBySQL("select * from Book where pages > ? and price < ?", "400", "20");

调用DataSupport.findBySQL()方法来进行原生查询,其中第一个参数用于指定SQL语句,后面的参数用于指定占位符的值,注意findBySQL()方法返回的是一个Cursor对象,需要将数据一一取出才行.

你可能感兴趣的:(Android 使用LitePal操作数据库)