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