Android FinalDb使用

本文介绍了Android ORM框架FinalDb的使用,包括新建项目、简单实用的API介绍、自定义数据库名和表名的方法,以及如何处理数据模型变更。通过注解实现Java Bean与SQLite数据库的映射,提供save、delete、find和update等基本操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载请标明出处:
http://blog.youkuaiyun.com/zq2114522/article/details/50691523
本文出自:【梁大盛的博客】

Android FinalDb使用

引:在不就之前接触到ORM,当然我接触的是afinal框架里面的FinalDb组件.一开始没看懂很多陌生的注解(之前对Java的注解也不是很清楚,对注解没什没什么概念).然后到后面看着看着发现应该是用注解结合数据库实现所谓的ORM.形成Java bean映射到Sql.事实上没猜错.(原谅哥没接触过ORM概念,之前使用数据库都是苦苦一条一条Sql语句组合起来.想想都觉得很挫!)

在Github上afinal最近一次维护已经是3年前的事情了.简直就是年久失修呀!不过也不妨碍对ORM的学习.后续会看看目前最流行的GREENDAO!

新建项目

在Android Studio中afinal做为一个模块出现.考虑到很多步骤附上小视频一个.胜过千言万语.

注意:在新版本Android Sdk里面已经不在包含org.apache.http.*
我们需要在Gradle配置文件里面添加:

这里写图片描述

useLibrary 'org.apache.http.legacy'

简单实用

详细具体在注释里面说清楚.

package com.example.dsliang.afinaldemo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import net.tsz.afinal.FinalDb;

import java.util.List;

import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.OnClick;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    FinalDb mFinalDb;
    @InjectView(R.id.editName)
    EditText editName;
    @InjectView(R.id.btnSave)
    Button btnSave;
    @InjectView(R.id.btnFind)
    Button btnFind;
    @InjectView(R.id.btnDel)
    Button btnDel;
    @InjectView(R.id.txtResult)
    TextView txtResult;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //ButterKnife注入
        ButterKnife.inject(this);

        FinalDb.DaoConfig daoConfig = new FinalDb.DaoConfig();
        daoConfig.setContext(this);
        mFinalDb = FinalDb.create(daoConfig);
    }

    @OnClick({R.id.btnSave, R.id.btnFind, R.id.btnDel})
    @Override
    public void onClick(View v) {
        String name;

        name = editName.getText().toString();


        switch (v.getId()) {
            case R.id.btnSave:
                Person person;

                if ("".equals(name)) {
                    Toast.makeText(this, "请输入名字", Toast.LENGTH_SHORT).show();

                } else {
                    person = new Person();
                    person.setName(name);
                    //保存Person到数据库
                    mFinalDb.save(person);
                }
                break;
            case R.id.btnFind:
                List<Person> list;
                StringBuffer stringBuffer;

                txtResult.setText("");

                if ("".equals(name)) {
                    //当为空字符串的时候查询所有
                    list = mFinalDb.findAll(Person.class);
                } else {
                    //根据name字段查询
                    list = mFinalDb.findAllByWhere(Person.class, "name=\"" + name + "\"");
                }

                if (0 != list.size()) {
                    stringBuffer = new StringBuffer();
                    for (Person p : list) {
                        stringBuffer.append("name[id: " + p.getId() + " name: " + p.getName() + "]\n");
                    }
                    txtResult.setText(stringBuffer.toString());
                } else {
                    Toast.makeText(this, "数据库不存在该记录", Toast.LENGTH_SHORT).show();
                }
                break;
            case R.id.btnDel:
                if ("".equals(name)) {
                    //当为空字符串的时候删除所有
                    mFinalDb.deleteAll(Person.class);
                } else {
                    //根据name字段删除
                    mFinalDb.deleteByWhere(Person.class, "name=\"" + name + "\"");
                }
                Toast.makeText(this, "完成删除操作", Toast.LENGTH_SHORT).show();
                break;
            default:
                break;
        }

        editName.setText("");
    }
}

效果图
这里写图片描述

注意:删除操作个人感觉并不是很友善.毕竟所提供的删除操作返回值竟然为void.有必要在进行删除操作之前先查询是否有该条记录然后进行删除操作.删除操作完毕以后在进行一次查询确保是否真的执行无误.

可以看到对数据库的操作我们通过saveXXX(…),deleteXXX(…),findXXX(),updateXXX(…)这四类函数完成.使用方法都是大同小异的不详细说明.

  • 现在看看finanDb具体帮我们生成了怎么样的数据库和对于bean的表.
    这里写图片描述
    可以看到默认是生成已”afinal”命名的数据库

  • 在看看Person类生成什么表
    这里写图片描述
    包名+类名的形式新建一个表

到这里大概对FinalDb有个了解.

再近一点看看

怎么实现自定义数据库名和表明.有兴趣进去到源码你可以发现都是通过注解实现个性化设置.

  • 说说关于主键的一些事情
    1. 首先查找ID注解
    2. 其次是_id字段
    3. 最后是id字段
    4. 当然以上均没找到那就抛出异常吧

在getPrimaryKeyColumn函数里面很清晰表明这种逻辑.
所以也知道为什么我没Person类里面会定义id字段了吧.此外id字段会自动复制我们无需理会.

    public static String getPrimaryKeyColumn(Class<?> clazz) {
        String primaryKey = null ;
        Field[] fields = clazz.getDeclaredFields();
        if(fields != null){
            Id idAnnotation = null ;
            Field idField = null ;

            for(Field field : fields){ //获取ID注解
                idAnnotation = field.getAnnotation(Id.class);
                if(idAnnotation != null){
                    idField = field;
                    break;
                }
            }

            if(idAnnotation != null){ //有ID注解
                primaryKey = idAnnotation.column();
                if(primaryKey == null || primaryKey.trim().length() == 0)
                    primaryKey = idField.getName();
            }else{ //没有ID注解,默认去找 _id 和 id 为主键,优先寻找 _id
                for(Field field : fields){
                    if("_id".equals(field.getName()))
                        return "_id";
                }

                for(Field field : fields){
                    if("id".equals(field.getName()))
                        return "id";
                }
            }
        }else{
            throw new RuntimeException("this model["+clazz+"] has no field");
        }
        return primaryKey;
    }
  • 主键的设置

    1. 使用ID注解
      public class Person {
      @Id
      int key;
      String name;
      ....
      }

    2. 使用_id字段
      public class Person {
      int _id;
      String name;
      ....
      }

    3. 使用id字段
      public class Person {
      int id;
      String name;
      ....
      }
  • 改变Person表名字
    接下来就是表明生成的逻辑.getTableName函数也是很清晰的说清楚怎么生成表名.

    1. 没找到Table注解的时候.默认用类的名称作为表名,并把点(.)替换为下划线(_)
    2. 找到Table那么就按照所设定的来命名
public static String getTableName(Class<?> clazz) {
        Table table = clazz.getAnnotation(Table.class);
        if(table == null || table.name().trim().length() == 0 ){
            //当没有注解的时候默认用类的名称作为表名,并把点(.)替换为下划线(_)
            return clazz.getName().replace('.', '_');
        }
        return table.name();
    }

使用Table注解实现自定义表名

@Table(name = "person")
public class Person {
...
}
  • 改变数据库名字

在新建数据库传递数据库名字即可了.


        FinalDb.DaoConfig daoConfig = new FinalDb.DaoConfig();
        daoConfig.setContext(this);
        daoConfig.setDbName("FinalDbDemo");
        mFinalDb = FinalDb.create(daoConfig);

        //或者
        //mFinalDb = FinalDb.create(this,"FinalDbDemo");

注意:daoConfig.setDebug(true)这个属性十分有用.
true:进行数据库操作的时候会打印sql语句(调试十分方便)
false:进行数据库操作的时候不打印sql语句

注意:创建数据的时候使用FinalDb.create(FinalDb.DaoConfig config)更方面配置数据库属性.

Person需求改了怎么办?

最后一部分说一说怎么利用DbUpdateListener更新数据库.
情景:
我们的软在1.0版本中Person只有两个字段分别是id和name.然后到1.1版本中添加了新字段.例如添加age字段了.怎么办?
在1.0版本的软件我们的程序在使用数据库的时候会传递一个数据库版本号(版本号为1)到数据库.当数据库操作完成以后会把这个版本好写道数据库里面.这个时候我们升级软件到1.1版本了.软件在此访问数据库,当然在1.1版本我们的数据库版本变成了2.此时发现我访问时候传递的版本号和数据库里面保存的不一致了.就会触发调用DbUpdateListener函数.

简单点就是,访问数据库的时候发现SqliteDbHelper(create函数传递的版本号)里面的版本号和数据库里面的不一样的时候会调用SqliteDbHelper函数.

举个例子:
我们的Demo程序现在改版了.需要给person加age字段.

Demo 1.0

        FinalDb.DaoConfig daoConfig = new FinalDb.DaoConfig();
        daoConfig.setContext(this);
        daoConfig.setDbName("FinalDbDemo");
        daoConfig.setDebug(true);
         //在1.0版本,数据版本号:1
        daoConfig.setDbVersion(1);
        daoConfig.setDbUpdateListener(new FinalDb.DbUpdateListener() {
            @Override
            public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

            }
        });
        mFinalDb = FinalDb.create(daoConfig);

Demo 1.1

        FinalDb.DaoConfig daoConfig = new FinalDb.DaoConfig();
        daoConfig.setContext(this);
        daoConfig.setDbName("FinalDbDemo");
        daoConfig.setDebug(true);
        //在1.1版本,数据版本号:2
        daoConfig.setDbVersion(2);
        daoConfig.setDbUpdateListener(new FinalDb.DbUpdateListener() {
            @Override
            public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
                //当1版本的数据升级到2版本的数据,我们需要给person表增加age字段
                if (oldVersion == 1 && newVersion == 2) {
                    db.execSQL("ALTER TABLE person ADD age  TEXT;");
                }
            }
        });
        mFinalDb = FinalDb.create(daoConfig);

数据的升级就是那么简单了!

效果:
这里写图片描述

总结:
FinalDb不得不说使用起来相当方便.很多操作都是简单一行代码完成.实现上通过java注解实现,像修改表名,主键等使用起来很简单.但是沦落到年久失修惨遭遗弃的地步.作为一个学习ORM它是不二的选择!相当值得一看!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值