Android官方ORM Room介绍

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/heheilije111/article/details/84915055

Android官方ORM Room介绍

基本使用

  1. 通过实体类和注解定义表数据:
Entity
public class User {
    @PrimaryKey
    public int uid;
    
    @ColumnInfo(name = "first_name")
    public String firstName;
    
    @ColumnInfo(name = "last_name")
    public String lastName;
}
  1. 创建具体操作的Dao接口类:
@Dao
public interface UserDao {
    @Query("SELECT * FROM user")
    List<User> getAll();

    @Query("SELECT * FROM user WHERE uid IN (:userIds)")
    List<User> loadAllByIds(int[] userIds);

    @Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
           "last_name LIKE :last LIMIT 1")
    User findByName(String first, String last);

    @Insert
    void insertAll(User... users);

    @Delete
    void delete(User user);
}
  1. 定义继承自RoomDatabase的数据库类,在这个类中定义创建Dao类的接口,是抽象类,Room将在编译时生成具体的实现类:
@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDao userDao();
}
  1. 在代码中使用:
//创建db对象
AppDatabase db = Room.databaseBuilder(getApplicationContext(),
        AppDatabase.class, "database-name").build();

//通过在AppDatabase中定义的接口方法获取Dao对象
UserDao userdao = db.userDao();

//调用Dao中对应方法执行操作
userDao.getAll();

数据定义

在Room中,每个表关联一个使用@Entity注解的实体类,表中的列关联到实体类的字段,表的列的属性通过实体类中注解来实现:

@Entity
public class User {
    @PrimaryKey
    public int id;

    public String firstName;
    public String lastName;
}

需要在@Database注解entities属性中声明实体类,Room会在编译时自动生成创建表的代码,并在初始化时创建表:

@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDao userDao();
}
  1. 主键
    a. 唯一主键;如上面的代码示例,通过在实体字段上添加@PrimaryKey可以声明该列为主键,@PrimaryKey 注解还包含autoGenerate属性,可以声明主键自动生成如:
 @PrimaryKey(autoGenerate = true)
 public int id;

b. 联合主键;当要定义联合主键时可以使用@Entity的属性primaryKeys,如:

@Entity(primaryKeys = {"firstName", "lastName"})
 public class User {
     public String firstName;
     public String lastName;
 }

 
2. 忽略实体字段;一般情况下,实体中所有字段都会在表中创建一个列,当要某些字段不需要创建列时,可以通过添加注解@Ignore将其忽略,如:
```
@Entity
public class User {
@PrimaryKey
public int id;

    public String firstName;
    public String lastName;

    @Ignore
    Bitmap picture;
}
```
也可以通过@Entity的属性ignoredColumns 来将其忽略,如:

```
@Entity(ignoredColumns = "picture")
public class RemoteUser extends User {
    @PrimaryKey
    public int id;

    public boolean hasVpn;
}
```
&nbsp;
  1. 查询优化;
    a. 索引;在Room中通过@Entity 的属性indices来建立索引,如:

    @Entity(indices = {@Index("name"),
            @Index(value = {"last_name", "address"})})
    public class User {
        @PrimaryKey
        public int id;
    		
        public String firstName;
        public String address;
    
        @ColumnInfo(name = "last_name")
        public String lastName;
    
        @Ignore
        Bitmap picture;
    }
    

b. 全文检索;SQLite3内置了全文检索的扩展模块——FTS,通过主键@FTS3、@FTS4分别启用基于FTS3和FTS4;如:
```
@Fts4
@Entity(tableName = “users”)
public class User {
// Specifying a primary key for an FTS-table-backed entity is optional, but
// if you include one, it must use this type and column name.
@PrimaryKey
@ColumnInfo(name = “rowid”)
public int id;

	    @ColumnInfo(name = "first_name")
	    public String firstName;
	}
```

 
4. 嵌套对象;有时候,一个表中的几个列在应用逻辑上更适合组合成一个实体,但是为这几个字段单独建表又感觉没必要,Room提供了@Embedded注解来解决这种情况:
```
public class Address {
public String street;
public String state;
public String city;

	    @ColumnInfo(name = "post_code")
	    public int postCode;
	}
	
	@Entity
	public class User {
	    @PrimaryKey
	    public int id;

	    public String firstName;
	
	    @Embedded
	    public Address address;
}
```
在上面例子中,会建立一个包含id、firstName、street、city、state、postCode的User表,而在在查询时street、city、state、postCode会自动组合成Address对象,反之亦然。

 
5. 视图;通过注解@DatabaseView可以创建视图,如:
@DatabaseView("SELECT user.id, user.name, user.departmentId," + "department.name AS departmentName FROM user " + "INNER JOIN department ON user.departmentId = department.id") public class UserDetail { public long id; public String name; public long departmentId; public String departmentName; }
同时,要在@Database中views属性中添加:
@Database(entities = {User.class}, views = {UserDetail.class}, version = 1) public abstract class AppDatabase extends RoomDatabase { public abstract UserDao userDao(); }

数据操作

在Room框架中,我们使用DAOs(data access objects)来对数据库中的数据进行操作。可以通过@Dao注解来声明一个Dao类的接口或者抽象类,每个操作对应一个抽象方法,注解@Insert、@Delete、@Update、@Query分别对应增删改查:

@Dao
public interface UserDao {
    @Insert
    void insertAll(User... users);
    @Update
    public void updateUsers(User... users);
    @Delete
    void delete(User user);
    @Query("SELECT * FROM user")
    List<User> getAll();
}

具体实现类会在编译时自动生成,使用时通过在Database类中定义的工厂方法获取:

@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDao userDao();
}
  1. 多种方法模板;对于不同的应用场景,Room提供了不同类型的方法:
    	@Dao
    	public interface MyDao {
    	    @Insert(onConflict = OnConflictStrategy.REPLACE)
    	    public void insertUsers(User... users);
    	
    	    @Insert
    	    public void insertBothUsers(User user1, User user2);
    	
    	    @Insert
    	    public void insertUsersAndFriends(User user, List<User> friends);
    	}
    
    每个方法都可以设置返回值,如果只操作一个数据(只有一个传入参数),则返回一个long型的数据,也就是被操作数据的rowID,如果操作一组数据则返回这一组数据的rowID,返回值应该long[] 或者 List< Long >。
     
  2. 查询参数绑定;Room可以通过:[参数名]的方式将参数注入到SQL查询语句中:
    @Dao
    public interface MyDao {
        @Query("SELECT * FROM user WHERE age BETWEEN :minAge AND :maxAge")
        public User[] loadAllUsersBetweenAges(int minAge, int maxAge);
    
        @Query("SELECT * FROM user WHERE first_name LIKE :search " +
               "OR last_name LIKE :search")
        public List<User> findUserWithName(String search);
    }
    

 
3. 返回列的子集;在数据库查询结果中经常会只需要某些字段,或者在多表联合查询中需要多张表的字段的情况,这些情况下直接返回定义表的实体对象是不合适的,Room允许你自定义POJO来映射结果集:
```
public class NameTuple {
@ColumnInfo(name = “first_name”)
public String firstName;

    @ColumnInfo(name = "last_name")
    public String lastName;
}
```
```
@Dao
public interface MyDao {
    @Query("SELECT first_name, last_name FROM user")
    public List<NameTuple> loadFullName();
}
```

 
Room默认是不允许在UI线程中进行数据操作的,如果要用需要在初始化时调用.allowMainThreadQueries()。基于这种设计哲学,Room对响应式框架非常友好。
 
4. LiveData;LiveData是Android官方提供的响应式框架,与Room的配合极其简单(Android官方架构工具直接的配合使用都很简洁);在gradle中配置好LiveData相关依赖后,只需要把对应操作的方法返回值用LiveData<>包裹就行了:
@Dao public interface MyDao { @Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)") public LiveData<List<User>> loadUsersFromRegionsSync(List<String> regions); }
 
5. RxJava;Room为不同的操作提供不同的可观察者对象:
a. 对于@Query,Room提供Publisher、Flowable和Observable;
b. 对于@Insert、@Update、 @Delete,Room提供Completable、Single和Maybe;
使用方式也简单:
首先在app/build.gradle中配置依赖
dependencies { implementation 'androidx.room:room-rxjava2:2.1.0-alpha02' }
然后和LiveData一样用泛型包裹返回值:
```
@Dao
public interface MyDao {
@Query(“SELECT * from user where id = :id LIMIT 1”)
public Flowable loadUserById(int id);

    // Emits the number of users added to the database.
    @Insert
    public Maybe<Integer> insertLargeNumberOfUsers(List<User> users);

    // Makes sure that the operation finishes successfully.
    @Insert
    public Completable insertLargeNumberOfUsers(User... users);

    /* Emits the number of users removed from the database. Always emits at
       least one user. */
    @Delete
    public Single<Integer> deleteUsers(List<User> users);
}
```

 
6. 直接返回Cursor;
@Dao public interface MyDao { @Query("SELECT * FROM user WHERE age > :minAge LIMIT 5") public Cursor loadRawUsersOlderThan(int minAge); }

依赖配置

Room属于官方依赖,提供了AndroidX版本和非AndroidX版本,配置都很简单:

  1. 非AndroidX:
dependencies {
    def room_version = "1.1.1"

    implementation "android.arch.persistence.room:runtime:$room_version"
    annotationProcessor "android.arch.persistence.room:compiler:$room_version" // use kapt for Kotlin

    // 可选- RxJava支持
    implementation "android.arch.persistence.room:rxjava2:$room_version"
}
  1. AndroidX:
dependencies {
    def room_version = "2.1.0-alpha03"

    implementation "androidx.room:room-runtime:$room_version"
    annotationProcessor "androidx.room:room-compiler:$room_version" // use kapt for Kotlin

    // 可选- RxJava支持
    implementation "androidx.room:room-rxjava2:$room_version"
}

如果要使用LiveData请参考Lifecycle的配置文档配置LiveData相关依赖。

猜你喜欢

转载自blog.csdn.net/heheilije111/article/details/84915055