您的位置:首页 > 移动开发 > Android开发

Android 快速开发系列 ORMLite 框架最佳实践

2016-05-06 14:35 513 查看

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/39122981,本文出自【张鸿洋的博客】
上一篇已经对ORMLite框架做了简单的介绍:Android
ORMLite 框架的入门用法~~本篇将介绍项目可能会使用到的一些用法,也为我们的使用ORMLite框架总结出一个较合理的用法。

通过上一篇的了解,我们使用ORMLite,需要自己写一个DatabaseHelper去继承OrmLiteSqliteOpenHelper,下面我们首先给出一个我认为比较靠谱的Helper的写法:

1、DatabaseHelper

[java]
view plain
copy





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

[java]
view plain
copy





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

类这么定义:

[java]
view plain
copy





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类暂且就两个属性:

[java]
view plain
copy





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

[java]
view plain
copy





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;  
    }  
  
}  

接下来看我们的测试类:

[java]
view plain
copy





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、即上述写法

[java]
view plain
copy





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的代码:

[java]
view plain
copy





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

测试代码:

[java]
view plain
copy





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());  
            }  
    }  

输出:

[java]
view plain
copy





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 

[java]
view plain
copy





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、更复杂的查询

[java]
view plain
copy





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中直接写如下代码:

[java]
view plain
copy





//事务操作  
        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

[java]
view plain
copy





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

Article与User做Join操作;

本篇主要想介绍在项目中如何写DataBaseHelper已经如何写BeanDao,以及列出了在项目中可能会用到的ORMLite的功能,如果需要详细了解,还请看ORMLite官方文档,源码中也会提供~~

源码点击下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ORMLite框架实践