Android 快速開發系列 ORMLite 框架最佳實踐

jopen 8年前發布 | 17K 次閱讀 Android開發 移動開發

轉載請標明出處:http://blog.csdn.net/lmj623565791/article/details/39122981,本文出自【張鴻洋的博客】

上一篇已經對ORMLite框架做了簡單的介紹:Android ORMLite 框架的入門用法~~本篇將介紹項目可能會使用到的一些用法,也為我們的使用ORMLite框架總結出一個較合理的用法。

通過上一篇的了解,我們使用ORMLite,需要自己寫一個DatabaseHelper去繼承OrmLiteSqliteOpenHelper,下面我們首先給出一個我認為比較靠譜的Helper的寫法:

1、DatabaseHelper

package com.zhy.zhy_ormlite.db;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;

import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;
import com.zhy.zhy_ormlite.bean.Article;
import com.zhy.zhy_ormlite.bean.Student;
import com.zhy.zhy_ormlite.bean.User;

public  class DatabaseHelper extends OrmLiteSqliteOpenHelper
{
    private static final String TABLE_NAME = "sqlite-test.db";

    private Map<String, Dao> daos = new HashMap<String, Dao>();

    private DatabaseHelper(Context context)
    {
        super(context, TABLE_NAME, null, 4);
    }

    @Override
    public void onCreate(SQLiteDatabase database,
            ConnectionSource connectionSource)
    {
        try
        {
            TableUtils.createTable(connectionSource, User.class);
            TableUtils.createTable(connectionSource, Article.class);
            TableUtils.createTable(connectionSource, Student.class);
        } catch (SQLException e)
        {
            e.printStackTrace();
        }
    }

    @Override
    public void onUpgrade(SQLiteDatabase database,
            ConnectionSource connectionSource, int oldVersion, int newVersion)
    {
        try
        {
            TableUtils.dropTable(connectionSource, User.class, true);
            TableUtils.dropTable(connectionSource, Article.class, true);
            TableUtils.dropTable(connectionSource, Student.class, true);
            onCreate(database, connectionSource);
        } catch (SQLException e)
        {
            e.printStackTrace();
        }
    }

    private static DatabaseHelper instance;

    /**
     * 單例獲取該Helper
     * 
     * @param context
     * @return
     */
    public static synchronized DatabaseHelper getHelper(Context context)
    {
        context = context.getApplicationContext();
        if (instance == null)
        {
            synchronized (DatabaseHelper.class)
            {
                if (instance == null)
                    instance = new DatabaseHelper(context);
            }
        }

        return instance;
    }

    public synchronized Dao getDao(Class clazz) throws SQLException
    {
        Dao dao = null;
        String className = clazz.getSimpleName();

        if (daos.containsKey(className))
        {
            dao = daos.get(className);
        }
        if (dao == null)
        {
            dao = super.getDao(clazz);
            daos.put(className, dao);
        }
        return dao;
    }

    /**
     * 釋放資源
     */
    @Override
    public void close()
    {
        super.close();

        for (String key : daos.keySet())
        {
            Dao dao = daos.get(key);
            dao = null;
        }
    }

}

1、整個DatabaseHelper使用單例只對外公布出一個對象,保證app中只存在一個SQLite Connection , 參考文章:http://www.touchlab.co/2011/10/single-sqlite-connection/

2、我們對每個Bean創建一個XXXDao來處理當前Bean的數據庫操作,當然真正去和數據庫打交道的對象,通過上面代碼中的getDao(T t)進行獲取

getDao為一個泛型方法,會根據傳入Class對象進行創建Dao,并且使用一個Map來保持所有的Dao對象,只有第一次調用時才會去調用底層的getDao()。

 

2、Bean的Dao

package com.zhy.zhy_ormlite.db;

import java.sql.SQLException;

import android.content.Context;

import com.j256.ormlite.dao.Dao;
import com.zhy.zhy_ormlite.bean.User;

public class UserDao
{
    private Context context;
    private Dao<User, Integer> userDaoOpe;
    private DatabaseHelper helper;

    public UserDao(Context context)
    {
        this.context = context;
        try
        {
            helper = DatabaseHelper.getHelper(context);
            userDaoOpe = helper.getDao(User.class);
        } catch (SQLException e)
        {
            e.printStackTrace();
        }
    }

    /**
     * 增加一個用戶
     * @param user
     */
    public void add(User user)
    {
        try
        {
            userDaoOpe.create(user);
        } catch (SQLException e)
        {
            e.printStackTrace();
        }

    }//...other operations


}

我們的所有的XXXDao遵循以上的風格~

好了,基本了解了我們的代碼的結構~~ps:如果覺得不合理可以留言指出,如果覺得不能接收,直接忽略。。。

 

3、ORMLite外鍵引用

現在我們有兩張表一張User,一張Article; 

Article中當然需要存儲User的主鍵,作為關聯~~那么在ORMLite中如何做到呢?

可能有人會直接在Article中聲明一個int類型userId屬性,當作普通屬性處理搞定,這種做法并沒有做,但是沒有體現出面向對象的思想。

面向對象是這樣的:Article屬于某個User

類這么定義:

package com.zhy.zhy_ormlite.bean;

import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;

@DatabaseTable(tableName = "tb_article")
public class Article
{
    @DatabaseField(generatedId = true)
    private int id;
    @DatabaseField
    private String title;
    @DatabaseField(canBeNull = true, foreign = true, columnName = "user_id")
    private User user;

    public int getId()
    {
        return id;
    }

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

    public String getTitle()
    {
        return title;
    }

    public void setTitle(String title)
    {
        this.title = title;
    }

    public User getUser()
    {
        return user;
    }

    public void setUser(User user)
    {
        this.user = user;
    }

    @Override
    public String toString()
    {
        return "Article [id=" + id + ", title=" + title + ", user=" + user
                + "]";
    }

}

不會去定義一個int類型的userId,而是直接定義一個User成員變量,表示本Article屬于該User;

然后在User user屬性上添加: @DatabaseField(canBeNull = true, foreign = true, columnName = "user_id")

canBeNull -表示不能為null;foreign=true表示是一個外鍵;columnName 列名

User類暫且就兩個屬性:

package com.zhy.zhy_ormlite.bean;

import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;

@DatabaseTable(tableName = "tb_user")
public class User 
{
    @DatabaseField(generatedId = true)
    private int id;
    @DatabaseField(columnName = "name")
    private String name;


    public User()
    {
    }

    public int getId()
    {
        return id;
    }

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

    public String getName()
    {
        return name;
    }

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

    @Override
    public String toString()
    {
        return "User [id=" + id + ", name=" + name 
                + "]";
    }





}

現在看我們的ArticleDao

package com.zhy.zhy_ormlite.db;

import java.sql.SQLException;
import java.util.List;

import android.content.Context;

import com.j256.ormlite.dao.Dao;
import com.zhy.zhy_ormlite.bean.Article;
import com.zhy.zhy_ormlite.bean.User;

public class ArticleDao
{
    private Dao<Article, Integer> articleDaoOpe;
    private DatabaseHelper helper;

    @SuppressWarnings("unchecked")
    public ArticleDao(Context context)
    {
        try
        {
            helper = DatabaseHelper.getHelper(context);
            articleDaoOpe = helper.getDao(Article.class);
        } catch (SQLException e)
        {
            e.printStackTrace();
        }
    }

    /**
     * 添加一個Article
     * @param article
     */
    public void add(Article article)
    {
        try
        {
            articleDaoOpe.create(article);
        } catch (SQLException e)
        {
            e.printStackTrace();
        }
    }

    /**
     * 通過Id得到一個Article
     * @param id
     * @return
     */
    @SuppressWarnings("unchecked")
    public Article getArticleWithUser(int id)
    {
        Article article = null;
        try
        {
            article = articleDaoOpe.queryForId(id);
            helper.getDao(User.class).refresh(article.getUser());

        } catch (SQLException e)
        {
            e.printStackTrace();
        }
        return article;
    }

    /**
     * 通過Id得到一篇文章
     * @param id
     * @return
     */
    public Article get(int id)
    {
        Article article = null;
        try
        {
            article = articleDaoOpe.queryForId(id);

        } catch (SQLException e)
        {
            e.printStackTrace();
        }
        return article;
    }

    /**
     * 通過UserId獲取所有的文章
     * @param userId
     * @return
     */
    public List<Article> listByUserId(int userId)
    {
        try
        {
            return articleDaoOpe.queryBuilder().where().eq("user_id", userId)
                    .query();
        } catch (SQLException e)
        {
            e.printStackTrace();
        }
        return null;
    }

}

接下來看我們的測試類:

public class OrmLiteDbTest extends AndroidTestCase
{
    public void testAddArticle()
    {
        User u = new User();
        u.setName("張鴻洋");
        new UserDao(getContext()).add(u);
        Article article = new Article();
        article.setTitle("ORMLite的使用");
        article.setUser(u);
        new ArticleDao(getContext()).add(article);

    }

    public void testGetArticleById()
    {
        Article article = new ArticleDao(getContext()).get(1);
        L.e(article.getUser() + " , " + article.getTitle());
    }

    public void testGetArticleWithUser()
    {

        Article article = new ArticleDao(getContext()).getArticleWithUser(1);
        L.e(article.getUser() + " , " + article.getTitle());
    }

    public void testListArticlesByUserId()
    {

        List<Article> articles = new ArticleDao(getContext()).listByUserId(1);
        L.e(articles.toString());
    }

分別測試,添加一個Article;通過Id獲取一個Article;通過Id獲取一個Article且攜帶User;通過userId獲取所有的Article;

主要看第三個:通過Id獲取一個Article且攜帶User,testGetArticleWithUser(id)

如何值傳一個Article的Id,然后能夠拿到Article對象,且內部的user屬性直接賦值呢?

兩種方式:

1、即上述寫法

article = articleDaoOpe.queryForId(id);
            helper.getDao(User.class).refresh(article.getUser());

2、在user屬性的注解上:@DatabaseField(canBeNull = true, foreign = true, columnName = "user_id", foreignAutoRefresh = true)

添加foreignAutoRefresh =true,這樣;當調用queryForId時,拿到Article對象則直接攜帶了user;

 

4、關聯一個集合

每個User關聯一個或多個Article,如果我在User中聲明一個Collection<Article> articles,我能否在查詢User的時候,一并能夠獲取到articles的值呢?

答案是可以的。在User中添加如下屬性,且注解如下:

@ForeignCollectionField
private Collection<Article> articles;

我們在UserDao中書寫查詢User的代碼:

public User get(int id)
    {
        try
        {
            return userDaoOpe.queryForId(id);
        } catch (SQLException e)
        {
            e.printStackTrace();
        }
        return null ;
    }

測試代碼:

public void testGetUserById()
    {
        User user = new UserDao(getContext()).get(1);
        L.e(user.getName());
        if (user.getArticles() != null)
            for (Article article : user.getArticles())
            {
                L.e(article.toString());
            }
    }
輸出:

09-07 22:49:06.484: E/zhy(7293): 張鴻洋
09-07 22:49:06.484: E/zhy(7293): Article [id=1, title=ORMLite的使用]
可以看到,我們通過一個queryForId,成功的獲取了User,以及User關聯的所有的Articles;

 

5、條件查詢QueryBuilder的使用

上述代碼其實已經用到了簡單的條件查詢了:

1、簡單的where等于

articleDaoOpe.queryBuilder().where().eq("user_id", userId).query();直接返回Article的列表

2、where and 

QueryBuilder<Article, Integer> queryBuilder = articleDaoOpe
                    .queryBuilder();
            Where<Article, Integer> where = queryBuilder.where();
            where.eq("user_id", 1);
            where.and();
            where.eq("name", "xxx");

            //或者
            articleDaoOpe.queryBuilder().//
                    where().//
                    eq("user_id", 1).and().//
                    eq("name", "xxx");

上述兩種都相當與:select * from tb_article where user_id = 1 and name = 'xxx' ; 

3、更復雜的查詢

where.or(
                    //
                    where.and(//
                            where.eq("user_id", 1), where.eq("name", "xxx")),
                    where.and(//
                            where.eq("user_id", 2), where.eq("name", "yyy")));

select * from tb_article where ( user_id = 1 and name = 'xxx' )  or ( user_id = 2 and name = 'yyy' )  ;

好了,再復雜的查詢估計也能夠湊出來了~~

6、updateBuilder、deleteBuilder

使用queryBuilder是因為我們希望執行完成查詢直接返回List<Bean>集合;

對于Update我們并不關注返回值,直接使用

articleDaoOpe.updateRaw(statement, arguments);傳入sql和參數即可~~

何必在那articleDaoOpe.updateBuilder().updateColumnValue("name","zzz").where().eq("user_id", 1);這樣的痛苦呢~~~

同理還有deleteBuilder還是建議直接拼寫sql,當然很簡單的除外,直接使用它的API~

7、事務操作

在我們的Dao中直接寫如下代碼:

//事務操作
        TransactionManager.callInTransaction(helper.getConnectionSource(),
                new Callable<Void>()
                {

                    @Override
                    public Void call() throws Exception
                    {
                        return null;
                    }
                });


8、其他操作

1、當Bean繼承BaseDaoEnabled時,可以使用bean.create(bean);bean.update(bean)一類操作

例如:

Student extends BaseDaoEnabled<Student, Integer>

Dao dao = DatabaseHelper.getHelper(getContext()).getDao(Student.class);
Student student = new Student();
student.setDao(dao);
student.setName("張鴻洋");
student.create();

前提dao需要手動設置,如果dao為null會報錯,尼瑪,我覺得一點用沒有。。。

2、Join

QueryBuilder<Article, Integer> articleBuilder = articleDaoOpe
                    .queryBuilder();
            QueryBuilder userBuilder = helper.getDao(User.class).queryBuilder();
            articleBuilder.join(userBuilder);

Article與User做Join操作;

 

本篇主要想介紹在項目中如何寫DataBaseHelper已經如何寫BeanDao,以及列出了在項目中可能會用到的ORMLite的功能,如果需要詳細了解,還請看ORMLite官方文檔,源碼中也會提供~~

 

 

源碼點擊下載

 

 

 

來自: http://blog.csdn.net//lmj623565791/article/details/39122981

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!