Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ORMapping in Android #204

Open
soapgu opened this issue Jun 18, 2023 · 0 comments
Open

ORMapping in Android #204

soapgu opened this issue Jun 18, 2023 · 0 comments
Labels

Comments

@soapgu
Copy link
Owner

soapgu commented Jun 18, 2023

  • 前言

由于Restful的流行,客户端的发展是越来越轻。客户端直接操作数据库的场景已经越来越少。
但是安卓本地数据库仍然有少量的应用场景。
安卓比较常用的是Sqlite数据库,但是我们并不是直接操作sql语句。而是使用一个Room的中间件。

简要的了解了一下room。你就会发现和.net 的一代经典EntityFramewrok非常近似。
EF是ORMapping的巅峰

  • 什么是ORM

ORM :对象关系映射(英语:Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),用于实现面向对象编程语言里不同类型系统的数据之间的转换。

O(面向对象) <-----> ORMapping <-----> R(面向关系)

这里主要有个抽象的过程,毕竟Database是百花齐放,如果把业务逻辑直接和数据库底层捆绑是很痛苦的事情,通过对象这个中间层来解耦可以大大提高效率。

  • 快速入门

  1. 依赖引用
    这里我们使用RxJava作为异步支持库
     def room_version = "2.5.1"
    implementation "androidx.room:room-runtime:$room_version"
    annotationProcessor "androidx.room:room-compiler:$room_version"
    implementation "androidx.room:room-rxjava3:$room_version"

第一次下载特别是第一次预编译速度比较慢

  1. 数据对象定义
@Entity(tableName = "records")
public class Record {
    @PrimaryKey(autoGenerate = true)
    public int id;

    @ColumnInfo(name = "name")
    public String name;

    @ColumnInfo(name = "create_time")
    public long createTime;
}

使用Entity注解定义表
使用ColumnInfo定义列
使用PrimaryKey定义主键,设置autoGenerate=true可以让数据库制定
自增长主键很有年代感。

  1. 定义Dao接口
    这应该是JAVA的概念,这里我理解为对数据做 CURD操作的接口
    这里我们直接做了“跳级”,同步方法还需要另外开线程执行基本被抛弃了。我直接使用Rx异步的api
@Dao
public interface RecordDao {
    @Query("SELECT * from records")
    public Single<List<Record>> loadAllRecords();

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    public Completable insertRecord(Record record);

    @Update
    public Completable updateRecord(Record record);


    @Query("SELECT * FROM records WHERE id = :id")
    public Single<Record> loadRecordById(int id);

    @Delete
    public Completable deleteRecords(List<Record> records);
}

这里@dao来修饰操作类

@query@update@delete@insert来修饰方法对应database的不同操作

注意这里只要声明方法就行了,并不需要实现
组件会帮我们自动生成实现类,这一点和retrofit2这个组件用法是一样的。

  1. Database抽象类
@Database(entities = {Record.class},version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract RecordDao recordDao();
}

更高一级的抽象,可以认为是Database的映射

db = Room.databaseBuilder(this.getApplicationContext() , AppDatabase.class,"test-db")
                .build();

这里应用部分,建议使用单实例,RoomDatabase并不是一个“轻量级”对象

  1. 应用常见故障
    这里数据库操作是不允许在UI线程执行的,这个和OKHttp的规矩差不多
    这里修改也比较简单,直接加subscribeOn(Schedulers.io())就行

load records error : java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.

  1. 插入数据代码
this.findViewById(R.id.btn_add).setOnClickListener( v-> {
            Record record = new Record();
            record.name = txt_name.getText().toString();
            Date date = new Date();
            record.createTime = date.getTime() / 1000;
            disposables.add( db.recordDao().insertRecord( record )
                    .subscribeOn(Schedulers.io())
                    .subscribe( ()-> Logger.i("save record ok"),
                            throwable -> Logger.e( throwable, "save record error" )));
        } );
图片

增加第一条记录

图片
  1. 查询数据代码
this.findViewById(R.id.btn_query).setOnClickListener( v -> {
            disposables.add( db.recordDao().loadAllRecords()
                            .subscribeOn(Schedulers.io())
                            .observeOn(AndroidSchedulers.mainThread())
                            .subscribe( records -> {
                                tv_count.setText( String.valueOf( records.size() ) );
                                String names = records.stream().map(t->t.name).collect(Collectors.joining(","));
                                tv_names.setText( names );
                            },
                            throwable -> Logger.e(throwable,"load records error")) );
        } );
  • 怎么查看数据?

对标SqlServer这种“传统数据库”,Sqllite总觉得缺点啥,对了。
我怎么用工具来看数据,独立于程序之外。

  1. 通过Android Studio的工具Database Inspector
图片

完美对标SQLServer的查询分析器,这里不细说了

  1. adb 方式
图片
  • 步骤就是先进入adb shell。

  • 然后进入到数据库目录,/data/data/{application name}/databases/

为啥没有权限?没关系要su一下哦

  • 输入sqlite3 {database name}命令,(这里不能直接按文档来,程序自建的数据库是没.db后缀名的)

  • 输入sql语句,可以输入多行记得用;结尾

  • 使用Ctrl+D或者.exit退出

  • 参考链接

  • 安卓开发者教程

  • Demo仓库

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant