Android官方ORM Room介绍

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

     

  3. 查询优化;
    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<User> 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"
    }
    
  2. 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相关依赖。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android Room 是一个 ORM(对象关系映射)库,用于在 Android 应用中轻松地使用 SQLite 数据库。如果你需要升级 Room 数据库,通常是在应用版本迭代或引入新功能时,可能需要更新数据模型、添加新的迁移操作或者调整现有表结构。以下是升级 Room 数据库的基本步骤: 1. **更新数据模型**:首先,检查 Room entity(实体类)是否需要更新。如果添加了新的字段或修改了现有字段的数据类型,记得在对应的 entity 类中进行相应的更改。 2. **修改迁移文件**:Room 使用 Migration(迁移)来管理数据库结构的变化。在 `app/src/main/java/[package]/db/Migration` 文件中,创建新的迁移步骤。每次迁移都应增加一个版本号,比如从 `0` 到 `1`,`1` 到 `2` 等。在这个过程中,要确保数据完整性,处理好旧数据和新增字段的关系。 - 如果是添加新字段,Room 会默认为 `NOT NULL` 和默认值,但可能需要根据实际情况调整。 - 对于删除字段,记得在迁移中设置适当的策略,如设置为 `NULL` 或清除数据。 3. **配置 Room Database**:在 `RoomDatabase` 子类中,确保正确设置了迁移规则,例如: ```kotlin @Database(entities = [YourEntity::class], version = RoomDatabase.VERSION, exportSchema = false) abstract class YourDatabase : RoomDatabase() { // ... override fun onCreate() { super.onCreate() Migration.migrate(this, yourDatabaseVersion) } } ``` 4. **运行迁移**:在应用启动时,Room 会自动执行迁移操作。如果在运行时发现版本不匹配,用户可能需要手动更新应用才能完成迁移。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值