Android Database Framework - LitePal Learning Notes

Keywords: Database xml encoding Android

Android Database Framework - LitePal Learning Notes

Sketch

LitePal is Guo Shen's masterpiece in 2014. Three years later, there was an update on github, so I came to study it, but it was very useful. Here I take notes. LitePal is an open source Android database framework. It uses the object relational mapping (ORM) model and encapsulates some of the most commonly used database functions in our daily development, so that it can complete all kinds of table building and deletion checking operations without writing a single line of SQL statements. And LitePal is "light" and jar packages are less than 100k and almost zero configuration, which is quite different from frameworks like hibernate.

github:https://github.com/LitePalFramework/LitePal

I. Basic Use of LitePal

1. Introducing Jar packages or dependencies

1) Use gradle dependencies

dependencies {
    compile 'org.litepal.android:core:1.5.0'
}

2) Importing jar packages

①jar Bag: https://github.com/LitePalFramework/LitePal/raw/master/downloads/litepal-1.5.0.jar

②Source package: https://github.com/LitePalFramework/LitePal/raw/master/downloads/litepal-1.5.0-src.jar

The jar package can be downloaded from the above address and copied to the libs directory.

2. Configure litepal.xml

Create a litepal.xml file in the assets directory and copy the following code into it:

<?xml version="1.0" encoding="utf-8"?>  
<litepal>  
    <dbname value="Database name" ></dbname>  

    <version value="Database version number for updating database" ></version>  

    <list>
        <!--Here is the class mapping-->  
    </list>  
</litepal>  

3. Configure LitePal Application

1) If you do not have a custom APP in your project, configure it directly in the manifest file as follows:

<manifest>  
    <application  
        android:name="org.litepal.LitePalApplication"  
        ...  
    >  
    ...  
    </application>  
</manifest>  

2) If you have a custom APP that inherits Application in your project:

(1) Replace extends Application with extends LitePal Application.

(2) Use your custom APP in the manifest file, such as MyApplication:

<manifest>  
    <application  
        android:name="com.example.MyApplication"  
        ...  
    >  
    ...  
    </application>  
</manifest> 

3) If your custom APP in your project inherits a third-party Application in a jar package (i.e., the source code cannot be modified):

Scenario 1:

  1. You can download LitePal's source code and copy all the code in the src directory directly to the src directory of your project.
  2. Then open the LitePalApplication class and change its inheritance structure to inherit from a third-party Application
  3. Let MyApplication inherit from LitePal Application so that all applications can work together.

Option two:

public class MyOwnApplication extends AnotherApplication {

    @Override
    public void onCreate() {
        super.onCreate();
        LitePal.initialize(this);
    }
    ...
}

2. Using LitePal to Build Tables

Example: Suppose that a News APP is developed, and a News sheet is needed to record News locally, because the framework is ORM framework, that is, a News newspaper is needed to represent the News sheet, and it only takes two steps to create a News sheet through the News class:

1. Create an entity class

public class News {  

    private int id;  

    private String title;  

    private String content;  

    private Date publishDate;  

    private int commentCount;  

    // Automatic Generation of get and set Method  
    ...  
} 

2. Modify the litepal.xml file in the assets directory

<?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>  
    </list>  
</litepal>  

III. Using LitePal to Upgrade Tables

There are two scenarios for updating tables:

  • (1) Additional table

  • (2) Modify the table structure

1. Add a table

Example: To add the function of recording comments to the above news APP, we need one more comment table, that is, one more comment class Comment (regardless of the relationship between tables, this upgrade only adds one more table).

1) Create entity classes according to upgrade requirements

public class Comment {  

    private int id;  

    private String content;  

    // Automatic Generation of get and set Method   
    ...  
}  

2) Modify the litepal.xml file in the assets directory

Upgrading requires a value of + 1 for version nodes.

<?xml version="1.0" encoding="utf-8"?>  
<litepal>  
    <dbname value="demo" ></dbname>  

    <version value="2" ></version>  

    <list>  
        <mapping class="com.example.databasetest.model.News"></mapping>  
        <mapping class="com.example.databasetest.model.Comment"></mapping>  
    </list>  
</litepal>  

2. Table structure before modification

Example: Assuming that the comment class Comment mentioned above is a publishDate attribute that is missing from the previous version, it needs to be added to the version to be released.

1) Modify entity classes according to upgrade requirements

public class Comment {  

    private int id;  

    private String content;  

    private Date publishDate;  //An additional attribute for publishing time

    // Automatic Generation of get and set Method   
    ...  
}  

2) Modify the litepal.xml file in the assets directory

<litepal>  
    <dbname value="demo" ></dbname>  

    <version value="3" ></version>  
    ...  
</litepal>  

4. Using LitePal to Establish Table Association

1. One-to-one:

Example: Each News article corresponds to a brief Introduction and a brief Introduction corresponds to a News article.

1) Holding references from the other party in a class

Introduction class

public class Introduction {  

    private int id;  

    private String guide;  

    private String digest;  

    // Automatic Generation of get and set Method  
}  

(2) News category (holding profiles)

public class News {  
    ...  
    private Introduction introduction;  //A news story corresponds to an introduction.

    // Automatic Generation of get and set Method  
}  

2) Modify the version number in litepal.xml, add new table references to entity classes, and update the database.

<?xml version="1.0" encoding="utf-8"?>  
<litepal>  
    <dbname value="demo" ></dbname>  

    <version value="4" ></version>  

    <list>  
        <mapping class="com.example.databasetest.model.News"></mapping>  
        <mapping class="com.example.databasetest.model.Introduction"></mapping>  
    </list>  
</litepal>  

2. Many-to-one:

Example: A news article (like News) has multiple comments (like Comment)

1) Holding a set of more parties in the fewer parties, and citing the fewer parties in the more parties.

(1) News category (less side)

public class News {  
    ...  
    private Introduction introduction;  

    private List<Comment> commentList = new ArrayList<Comment>(); //A piece of news corresponds to multiple comments 

    // Automatic Generation of get and set Method  
}  

(2) Brief Category (more than one side)

public class Comment {  
    ...  
    private News news;  //A comment corresponds to a news story.

    // Automatic Generation of get and set Method   
}  

2) Modify the version number in litepal.xml and update the database.

<?xml version="1.0" encoding="utf-8"?>  
<litepal>  
    <dbname value="demo" ></dbname>  

    <version value="5" ></version>  

    <list>  
        <mapping class="com.example.databasetest.model.News"></mapping> 
        <mapping class="com.example.databasetest.model.Introduction"></mapping>  
        <mapping class="com.example.databasetest.model.Comment"></mapping>  
    </list>  
</litepal>  

3. Many-to-many:

Example: Category-like news, such as the iPhone 2000 release, can be mobile phone, technology, or headlines.

1) Holding each other's collection

News class

public class News {  
    ...  
    private Introduction introduction;  

    private List<Comment> commentList = new ArrayList<Comment>();  

    private List<Category> categoryList = new ArrayList<Category>();  //A piece of news corresponds to many categories

    // Automatic Generation of get and set Method  
} 

Category class

public class Category {  
    ...  
    private List<News> newsList = new ArrayList<News>();  //A Category Corresponds to Multiple News

    // Automatic Generation of get and set Method  
} 

2) Modify the version number in litepal.xml and update the database.

<?xml version="1.0" encoding="utf-8"?>  
<litepal>  
    <dbname value="demo" ></dbname>  

    <version value="6" ></version>  

    <list>  
        <mapping class="com.example.databasetest.model.News"></mapping>  
        <mapping class="com.example.databasetest.model.Comment"></mapping>  
        <mapping class="com.example.databasetest.model.Introduction"></mapping>  
        <mapping class="com.example.databasetest.model.Category"></mapping>  
    </list>  
</litepal> 

5. Storage operations using LitePal (add)

Because LitePal can create or upgrade tables through a common entity class, there is no requirement to inherit the specified class or implement the specified interface. However, if you want to store tables, there is a requirement that these entity classes must inherit DataSupport.

1. Let the entity class inherit DataSupport

public class News extends DataSupport{  

    ......  

    // Automatic Generation of get and set Method  
}  

2. Use save() to save individual entity data

Example: Preserving a news story

News news = new News();  
news.setTitle("This is a news headline.");  
news.setContent("It's a piece of news.");  
news.setPublishDate(new Date());  
news.save();  
  • tip:save() does not throw an exception and returns boolean.

Conventional ways of judging whether data is successfully saved are as follows:

if (news.save()) {  
    Toast.makeText(context, "Storage success", Toast.LENGTH_SHORT).show();  
} else {  
    Toast.makeText(context, "Storage failure", Toast.LENGTH_SHORT).show();  
} 

3. Use saveThrows() to save individual entity data

Example: Preserving a news story

News news = new News();  
news.setTitle("This is a news headline.");  
news.setContent("It's a piece of news.");  
news.setPublishDate(new Date());  
news.saveThrows();  
  • tip:saveThrows() throws an exception when the save fails, so you can handle the storage failure by capturing the exception.

3. Use DataSupport.saveAll() to save multiple entity data

List<News> newsList;  
...  
DataSupport.saveAll(newsList);  

4. Data preservation of many-to-one relationships

Comment comment1 = new Comment();  
comment1.setContent("Praise!");  
comment1.setPublishDate(new Date());  
comment1.save();                                    //The first comment was saved.
Comment comment2 = new Comment();  
comment2.setContent("Praise one.");  
comment2.setPublishDate(new Date());  
comment2.save();                                    //The second comment was saved.  
News news = new News();  
news.getCommentList().add(comment1);  
news.getCommentList().add(comment2);                //Add the first two saved comments to the comments collection of the News object
news.setTitle("Article 2 News Title");  
news.setContent("Article 2 News Contents");  
news.setPublishDate(new Date());  
news.setCommentCount(news.getCommentList().size());  
news.save();                                        //Save the News object

5. Use saveAsync() to save individual data asynchronously

News news = new News();  
news.setTitle("This is a news headline.");  
news.setContent("It's a piece of news.");  
news.setPublishDate(new Date()); 
news.saveAsync().listen(new SaveCallback() {
    @Override
    public void onFinish(boolean success) {

    }
});

6. When the data is saved successfully, the id in the object is assigned.

When the save() method or saveThrows() method is successfully stored, LitePal automatically assigns the corresponding id of this data to the id field of the entity class.
Here's an experiment:

News news = new News();  
news.setTitle("This is a news headline.");  
news.setContent("It's a piece of news.");  
news.setPublishDate(new Date());  
Log.d("TAG", "news id is " + news.getId());  
news.save();  
Log.d("TAG", "news id is " + news.getId());  

The printing results are as follows:

news id is 0
news id is 1

6. Modification and deletion operations using LitePal (deletion)

There are two ways to modify and delete using LitePal:

  • Use static methods in DataSupport classes (that is, entity classes do not need to inherit DataSupport).
  • (2) Use methods inherited from the entity class of DataSupport.

* tip: The ContentValues class must be used in Mode 1, but not in Mode 2.

1. Modification

1) Modify the data for the specified id

(1) Use the update() static method in the DataSupport class:

DataSupport. update (entity class. class, ContentValues, id value)

ContentValues values = new ContentValues();  
values.put("title", "today iPhone6 Release");  
DataSupport.update(News.class, values, 2);  
(2) Using methods inherited from the entity class of DataSupport:

obj.update(id value)

News updateNews = new News(); //News must inherit DataSupport
updateNews.setTitle("today iPhone6 Release");  
updateNews.update(2);  

2) Modify data for specified conditions

(1) Use the updateAll() static method in the DataSupport class:

DataSupport. updateAll (entity class. class, ContentValues, conditional group)

ContentValues values = new ContentValues();  
values.put("title", "today iPhone6 Plus Release");  
DataSupport.updateAll(News.class, values, "title = ? and commentcount > ?", "today iPhone6 Release", "0");  
(2) Using methods inherited from the entity class of DataSupport:

Obj. updateAll (conditional group)

News updateNews = new News();  //News must inherit DataSupport
updateNews.setTitle("today iPhone6 Release");  
updateNews.updateAll("title = ? and commentcount > ?", "today iPhone6 Release", "0"); 

3) Modify the whole table data

DataSupport. updateAll (entity class. class, ContentValues)

Example: Change the headlines of all news items in the news table to "Today's iPhone 6 Release".

ContentValues values = new ContentValues();  
values.put("title", "today iPhone6 Plus Release");  
DataSupport.updateAll(News.class, values);  

4) Modify the corresponding fields to default values

obj.setToDefault("field name")

This method is aimed at inheriting the entity class of DataSupport!!!

News updateNews = new News();  //News must inherit DataSupport
updateNews.setToDefault("commentCount");  
updateNews.updateAll();  

2. Delete operation

* There are three things to note about the deletion operation:

  • Only the persistent data can be deleted, so-called persistent data, commonly speaking, the data saved, that is, the data saved or queried can be deleted.
  • If the deleted data id is a foreign key in another table, the associated data in another table will also be deleted when the data is deleted.
  • The entity class inherited from DataSupport has no deleteAll method, so there is only one way to delete the specified condition data (that is, DataSupport.deleteAll()).

1) Delete data with specified id

(1) Use delete() static method in DataSupport class:

DataSupport. delete (entity class. class, id value)

DataSupport.delete(News.class, 2);  
(2) Using methods inherited from the entity class of DataSupport:

obj.delete(id value)

Here is a News object, which is obviously not persistent. Calling the delete() method at this time will not delete any data.

News news = new News();  
news.delete();  

If we have persisted this object before, then calling delete() method will delete the corresponding data of this object.

News news = new News();  
news.setTitle("This is a news headline.");  
news.setContent("It's a piece of news.");  
news.save();  
...  
news.delete();  

You can use the isSaved() method in DataSupport to determine whether an object is persistent.

News news;  
...  
if (news.isSaved()) {  
    news.delete();  
}  

2) Delete data with specified conditions

DataSupport. deleteAll (entity class. class, condition group)

DataSupport.deleteAll(News.class, "title = ? and commentcount = ?", "today iPhone6 Release", "0");

3) Delete full table data

DataSupport. deleteAll (entity class. class)

DataSupport.deleteAll(News.class);  

7. Queries Using LitePal (Check)

1. Simple Query

1) Query single data

(1) Query specified id data

News news = DataSupport.find(News.class, 1);

(2) Query the first data

News firstNews = DataSupport.findFirst(News.class);

(3) Query the last data

News lastNews = DataSupport.findLast(News.class);

2) Query multiple data

(1) Queries specify multiple id data

//Method 1:
List<News> newsList = DataSupport.findAll(News.class, 1, 3, 5, 7);

//Mode two:
long[] ids = new long[] { 1, 3, 5, 7 };  
List<News> newsList = DataSupport.findAll(News.class, ids);

(2) All data in the query table

List<News> allNews = DataSupport.findAll(News.class);    

2. Linked Query

Examples: Query items 11 to 20 with more than 0 comments in the news table, and present them in reverse order of publication time, with only two columns of "title" and "content".

The general sql statements are as follows:

select title,content from news where commentcount > 0 order by publishdate desc limit 10,10;

Using LitePal's link query, the code is as follows:

List<News> newsList = DataSupport.select("title", "content")
                                 .where("commentcount > ?", "0")
                                 .order("publishdate desc")
                                 .offset(10)
                                 .limit(10)
                                 .find(News.class);

* tip: select, where, order, offset, limit can be placed arbitrarily, and can be deleted arbitrarily according to their own needs, but find can not be removed.

3. Radical Query

LitePal's default query is lazy query, that is, only data in the form can be queried, and data in the associated table can not be found.

1) How to Use Radical Query

If you need to find the data in the associated table together (radical query), you can set the last parameter of the find() method (boolean isEager) to true, such as:

News news = DataSupport.find(News.class, 1, true);  
List<Comment> commentList = news.getCommentList();  

2) Disadvantages of radical query:

  • Once there is a lot of data in the associated table, the query speed may be very slow.
  • Radical queries can only query the associated table data of a specified table, but cannot continue to iterate over the associated table data of the associated table.

3) Use lazy query instead of radical query

Radical queries are not recommended by LitePal. Lazy queries are recommended. If lazy queries are to be used, the following modifications can be made to the entity class to achieve the query of the associated tables:

public class News extends DataSupport{      
    ...  
    public List<Comment> getComments() {  
        return DataSupport.where("news_id = ?", String.valueOf(id)).find(Comment.class);  
    }  
}

* tip: The associated data is queried only when the getComments() method is called. This approach is more efficient and reasonable than radical queries.

4. Primary Query

DataSupport.findBySQL (conditional group);

Cursor cursor = DataSupport.findBySQL("select * from news where commentcount>?", "0");  

8. Aggregation Functions Using LitePal

LitePal provides five aggregation functions: count(), sum(), average(), max() and min().

1,count()

The count() method is mainly used to count rows.

DataSupport. count (entity class. class)

Example: How many rows are there in the statistics news table

int result = DataSupport.count(News.class); 
//Increase query conditions by using affix query
int result = DataSupport.where("commentcount = ?", "0").count(News.class);  

2,sum()

sum() method is mainly used to find the results.

DataSupport. sum (Entity class, class, required fields, result type)

Example: Statistics the total number of comments in the news table

int result = DataSupport.sum(News.class, "commentcount", int.class); // It can also be float, double  

* tip: If the required fields are illegal, such as String, the return result is 0.

3,average()

average() method is mainly used for statistical average.

Data Support. average (Entity class. class, "field requiring average")

Example: Statistics of how many comments per news item is on average in the news table

double result = DataSupport.average(News.class, "commentcount");  //The default return value is double, because the average is usually decimal.
                                                                //Use double to maximize the program's decimal accuracy.

* tip: If a field requiring an average is illegal, such as String, the return result is 0.

4,max()

The max() method is mainly used to find the maximum value in a column.

DataSupport. Max (Entity class, class, field requiring maximum value, result type)

Example: What is the highest number of comments on all news in the news table?

int result = DataSupport.max(News.class, "commentcount", int.class);

5,min()

min() method is mainly used to find the smallest value in a column.

DataSupport.min (Entity class. class, "Fields Requiring Minimum Values", Result Type)

Example: What is the minimum number of comments in all the news in the news table?

int result = DataSupport.min(News.class, "commentcount", int.class);  

9. Constraining fields with annotations

The field can be constrained by using annotation @Column. There are four constraints as follows:

@Column(unique = true)              //Is it unique?
@Column(defaultValue = "unknown")   //Specify field defaults
@Column(nullable = false)           //Can it be empty?
@Column(ignore = true)              //Is it negligible?

Example: A news sheet, the main key is unique, the title can not be empty, the content has default values.

public class News extends DataSupport {  

    @Column(unique = true)
    private int id;  

    @Column(nullable = false)
    private String title;  

    @Column(defaultValue = "I am content.")
    private String content;  

    private Date publishDate;  

    private int commentCount;  

    // Automatic Generation of get and set Method  
    ...  
} 

Support for multiple databases

If multiple databases are used in the project, LitePal can also support creating multiple databases while the program is running. :

1. Create a brand new database

LitePalDB litePalDB = new LitePalDB("db2", 1);  //Create a second database named "db2"
litePalDB.addClassName(Singer.class.getName()); //Associate entity classes such as Singer with db2
litePalDB.addClassName(Album.class.getName());
litePalDB.addClassName(Song.class.getName());
LitePal.use(litePalDB);                         //Using db2 database

2. Create a database with the same structure as the old database

The structure means the same as the old database: litepal.xml configuration.

LitePalDB litePalDB = LitePalDB.fromDefault("New database name");
LitePal.use(litePalDB);

3. Change back to the default database (old database)

LitePal.useDefault();

4. Delete any database

LitePal.deleteDatabase("Database name");

Posted by richrock on Sun, 14 Apr 2019 21:06:32 -0700