Android Room DataBase

 

Room:
Entity --类,一张表,类名即表名,字段名 即表中字段名
Dao --CURD, 对Entity的操作
DataBase --- extends RoomDataBase


@PrimaryKey(autoGenerate = true) // 主键值自动增长
private int id;


// 联合主键
@Entity(primaryKeys = {"firstName", "lastName"})
class User {
public String firstName;
public String lastName;

@Ignore
Bitmap picture;
}

//通过如下tableName定义一个和类名不同的表名,alias
@Entity(tableName = "users")
public class User {
...
}

// 通过@ColumnInfo注解的name属性,来定义一个与字段名不同的列名
@Entity
public class User {
@ColumnInfo(name = "first_name")
private String firstName;

@ColumnInfo(name = "last_name")
private String lastName;
}

// 创建索引 indices, 以提高查询效率
@Entity(indices = {@Index("name"),
@Index(value = {"last_name", "address"})})

class User {
@PrimaryKey
public int id;

public String firstName;
public String address;

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

@Ignore
Bitmap picture;
}

// 唯一性约束(unique)
@Entity(indices = {@Index(value = {"first_name", "last_name"},
unique = true)})

class User {
@PrimaryKey
public int id;

public String firstName;
public String address;

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

@Ignore
Bitmap picture;
}


// 创建外键 foreignKeys - Room 允许通过创建外键的形式,来绑定多个Entity之间的关系,来确保数据的完整性
@Entity(foreignKeys = @ForeignKey(entity = User.class,
parentColumns = "id",
childColumns = "user_id")) // 这里parentColumns id 来着表User中,childColumns user_id来自于表 Book

class Book {
@PrimaryKey
public int bookId;

public String title;

@ColumnInfo(name = "user_id")
public int userId;
}


// 在Entity中创建自定义类型字段(Embedded)
class Address {
public String street;
public String state;
public String city;

@ColumnInfo(name = "post_code")
public int postCode;
}

@Entity
class User {
@PrimaryKey
public int id;

public String firstName;

@Embedded
public Address address; // 这里嵌套的自定义字段,来自类Address
}

// 有几点需要注意的:
// 1、此时,数据表User,并没有一列叫做address的。而是一共有6列数据,分别是:id, firstName, street, state, city, post_code。
// 2、自定义类型字段里面,可以嵌套另一个自定义类型字段。


// 基于上面的情况,可能会出现一种情况,就是当一个Entity中存在多个相同的自定义类型的时候,
// 你可能想要为区分每一个自定义类型的字段

// 举例如下:
// 1、有一个普通Java类Coordinate,代表坐标,包含两个表示经纬度的字段:longitude 和 latitude。
// 2、有一个Entity类Coordinates,代表多个国家的坐标,包含两个类型为Coordinate的字段,分别表示中国和英国的坐标:chinaCoordinate和englandCoordinate

@Entity
public class Coordinates {
// 代表英国的坐标,存到表中后,该类的字段会变成latitude和longitude
@Embedded
private Coordinate englandCoordinate;

// 代表中国的坐标,存到表中后,该类的字段会变成latitude和longitude
@Embedded
private Coordinate chinaCoordinate;
}

// 代表坐标
class Coordinate {
@ColumnInfo(name = "latitude")
private long latitude;

@ColumnInfo(name = "longitude")
private long longitude;
}

// 如上Entity表只会存在两个字段,分别是latitude和longitude。这样,我们就无法,分别的为中国和英国的坐标做出区分

// =》 通过 @Embedded 提供的prefix属性: 区分两个国家分别的经纬度
@Entity
public class Coordinates {
// 代表中国的坐标,存到存储库里面后,该类的字段会变成CN_latitude和CN_longitude
@Embedded(prefix = "CN_")
private Coordinate chinaCoordinate;

// 代表英国的坐标,存到存储库里面后,该类的字段会变成UK_latitude和UK_longitude
@Embedded(prefix = "UK_")
private Coordinate englandCoordinate;
}

// 代表坐标
class Coordinate {
@ColumnInfo(name = "latitude")
private long latitude;

@ColumnInfo(name = "longitude")
private long longitude;
}

// 按如上修改后,Coordinates 表中将会存在四个字段,分别是:CN_latitude、CN_longitude、UK_latitude和UK_longitude


// 在Room中,Dao是一组操作数据库表的行为的集合。它即可用接口的形式,也可用抽象类的形式来表现。换言之,创建一个Dao,即是创建一个接口或是一个抽象类。如果是以抽象类的形式,那这个Dao,可以携带一个RoomDataBase类型的参数,这个暂时没发现有什么用处。

// 定义Dao
@Dao
public interface UserDao {
@Query("select * from UserInfo")
List<UserInfo> getAll();

// 首先,from 后面的表名所代表的类,必须是一个Entity。然后,where 后面的条件字段,必须是该Entity里面的字段。最后,匹配的条件,必须与方法的参数名一致。
@Query("select * from UserInfo where id in (:userIds")
List<UserInfo> loadAllByIds(int[] userIds);

@Query("select * from UserInfo wehre first_name like : first and last_name like : last limit 1")
UserInfo findByName(String first, String last);

@Query("select id, first_name, last_name from UserInfo where id = :id")
UserInfo getUserInfoById(int id);

@Insert(onConflict = OnConflictStrategy.REPLACE)
long[] insertAll(UserInfo... users);

@Update
void update(UserInfo... users);

@Delete
void delete(UserInfo user);
}

// 定义一个Dao,只要注意这几点即可:

// 1、Dao必须是接口或是抽象类。
// 2、像定义Entity一样,在Dao的定义的前一行,加上注解@Dao即可。
// 3、Dao下的所有方法,都有一个注解。不同的注解,代表不同的意思,比如增删查改。而这些SQL语句是否合法,会在编译阶段就先过滤。如果你的SQL语句写错了,那将会编译失败。

 

code snippets:

@Entity
public class userInfo {
    @PrimaryKey
    private int id;

    @ColumnInfo(name = "first_name")
    private String firstName;

    @ColumnInfo(name = "last_name")
    private String lastName;

    @Ignore
    private int sex;

    private int getId() {
        return id;
    }

    private void setId(int id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;

    }
}

@Dao
public interface UserDao {
    @Query("SELECT * FROM UserInfo")
    List<userInfo> getAll();

    @Query("SELECT * FROM UserInfo WHERE id in (:userIds)")
    List<userInfo> loadAllByIds(int[] userIds);

    @Query("SELECT * FROM UserInfo WHERE first_name LIKE :first AND last_name LIKE :last limit 1")
    List<userInfo> findByName(String first, String last);

    @Query("SELECT id, first_name, last_name FROM UserInfo WHERE id = :id")
    userInfo getUserInfoById(int id);

    // (onConflict = OnConflictStrategy.REPLACE),这段表示,如果插入有冲突,就直接替换掉旧的数据
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    long[] insertAll(userInfo... users);

    @Delete
    void delete(userInfo user);

    @Update
    void update(userInfo user);
}

@Database(entities = { userInfo.class }, version = 1)
public abstract class UserDatabase extends RoomDatabase {
    public abstract UserDao getUserDao();}

    // 通过Room的databaseBuilder,获取到UserDataBase的对象
    UserDatabase db = Room.databaseBuilder(getApplicationContext(),
            UserDatabase.class, "UserDataBase").build();

    // 通过UserDataBase,获取UserDao对象
    UserDao userDao = db.getUserDao();

    // 通过UserDao对象,对UserInfo表进行操作, 比如,通过用户id,来查询并获取一个UserInfo对象
UserInfo userInfo = userDao.getUserInfoById(007);

    // 打印, 用户信息
    if(userInfo!=null)
    {
        Toast.makeText(MainActivity.this, "query failed! ", Toast.LENGTH_SHORT).show();
    }else
    {
        Toast.makeText(MainActivity.this, "userName is " + userInfo.getFirstName() + " " + userInfo.getLastName(),
                Toast.LENGTH_SHORT).show();
    }

    // 通过UserDao对象,对UserInfo表进行操作, 比如,插入一个UserInfo对象
    UserInfo newUser = new UserInfo(008, "John", "Doe", 1);userDao.insertAll(newUser);

    // 关闭数据库
    db.close();

    // 查询用户信息
private void queryUserInfo() {
    List<UserInfo> userInfoList = userDao.getAll();
    for (UserInfo userInfo : userInfoList) {
        Log.d(TAG, "queryUserInfo: " + userInfo.getId() + " " + userInfo.getFirstName() + " " + userInfo.getLastName());
    }

    // 插入用户信息
    private void insertUserInfo() {
        UserInfo userInfo = new UserInfo(009, "Jane", "Doe", 0);
        userDao.insertAll(userInfo);
    }

    // 删除用户信息
    private void deleteUserInfo() {
        UserInfo userInfo = new UserInfo(009, "Jane", "Doe", 0);
        userDao.delete(userInfo);
    }

    // 更新用户信息
    private void updateUserInfo() {
        UserInfo userInfo = new UserInfo(008, "John", "Doe", 1);
        userDao.update(userInfo);
    }

    // 查询用户信息,加上RxJava2
    private void queryUserInfo2() {
        ThreadManager.execute(new SubscribeListener<UserInfo>() {
            @Override
            public UserInfo runOnSubThread() throws Exception {
                UserDao userDao = UserDataBase.getInstance(MainActivity.this).getUserDao();
                return userDao.getUserInfoById(007);
            }
        }, new ObserverListener<UserInfo>() {
            @Override
            public void runOnUiThread(@Nullable UserInfo userInfo) {
                if (userInfo == null) {
                    Toast.makeText(MainActivity.this, "query failed! ", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(MainActivity.this,
                            "userName is " + userInfo.getFirstName() + " " + userInfo.getLastName(), Toast.LENGTH_SHORT)
                            .show();
                }
            }

            @Override
            public void onNext(UserInfo userInfo) {
                if (userInfo != null) {
                    Toast.makeText(MainActivity.this, "query failed! ", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(MainActivity.this,
                            "userName is " + userInfo.getFirstName() + " " + userInfo.getLastName(), Toast.LENGTH_SHORT)
                            .show();
                }
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "queryUserInfo2: ", e);
            }

            @Override
            public void onComplete() {
                Log.d(TAG, "queryUserInfo2: onComplete");
            }
        });
}

 

Android Room DataBase(一)
https://blog.csdn.net/l_o_s/article/details/79346426

Android Room DataBase(二)
https://blog.csdn.net/l_o_s/article/details/79348701

Android Room DataBase(三)
https://blog.csdn.net/l_o_s/article/details/79388408

使用 Android Jetpack 的 Room 部分将数据保存到本地数据库
https://developer.android.com/training/data-storage/room?hl=zh-cn

使用 Room 实体定义数据
https://developer.android.com/training/data-storage/room/defining-data?hl=zh-cn#kotlin

posted @ 2024-03-06 18:30  petercao  阅读(13)  评论(0编辑  收藏  举报