您通常会有一个 POJO 来表示组合数据。然后,您可以为提取的列提供一个字段/变量,注意值与喜欢的命名变量匹配。
您可以使用@Embedded 将实体包含在其整体中,因此理论上嵌入地址城市和州。
您可以将@Embedded 与@Relation 一起用于子(子),但不能用于孙(例如州)。您将需要一个带有 State POJO 的基础 City,其中 City 是嵌入的,State 通过 @Relation 关联。
- 当使用 @Relation 作为房间从父级构建底层查询时,变量/列名不是问题。
变量/列名问题
Room 根据变量名称将列映射到变量。因此,如果对所有三个实体都使用更简单的 @Embedded,则id和name列将会出现问题。
我建议始终使用唯一的名称,例如 addressId、cityId、StateId(至少对于列名,例如 @ColumnInfo(name = "addressId")),但更简单的是只有 var addressid。
另一种方法是在一些上使用@Embedded(prefix = "the_prefix"),这告诉房间将变量与带有前缀的列名匹配,因此您需要在SQL中使用AS。显然 the_prefix 将被更改以适应。
道的
如果将@Embedded 与@Relation 一起使用,那么您只需要获取父级
@Query("SELECT * FROM address")
fun getAddressWithCityAndWithState(): List<AddressWithCityAndWithState>
- 其中 AddressWithCityAndWithState 是具有地址@Embedded 和具有@Relation 的CityWithState 的POJO。
您还需要带有 City @Embedded 的 CityWithState POJO 和带有 @Relation 的 State。
如果嵌入地址、城市和州,城市的前缀为“city_”,州的前缀为“state_”,那么您将使用类似:-
@Query("SELECT address.*, city.id AS city_id, city.name AS city_name, state.id AS state_id, state.name AS state_name FROM address JOIN city ON address.cityfk = city.it JOIN state ON city.statefk = state.id")
fun getAddressWithCityAndWithState(): List<AddressWithCityAndWithState>
- 其中 AddressWithCityAndWithState 是具有地址、城市和州 @Embedded 的 POJO
注意以上是原则性的。
工作示例
以下是基于的工作示例
- a) 重命名列以避免歧义和
- b) 在 POJO AddressWithCityWithState中使用所有三个类的 @Embedded
首先更改地址、城市和州以重命名列:-
地址:-
@Entity(
foreignKeys = [
ForeignKey(
entity = City::class,
parentColumns = arrayOf("city_id"), //<<<<<<<<<< CHANGED
childColumns = arrayOf("cityfk"),
onDelete = ForeignKey.NO_ACTION
)
]
)
data class Address(
@PrimaryKey
@ColumnInfo(name ="address_id") //<<<<<<<<<< ADDED name
var id: Long = 0
) : Serializable {
@ColumnInfo(name = "address_name") //<<<<<<<<<< ADDDED name
var name: String = ""
@ColumnInfo(index = true)
var cityfk: Long = 0
}
城市:-
@Entity(
foreignKeys = [
ForeignKey(
entity = State::class,
parentColumns = arrayOf("state_id"), //<<<<<<<<<< changed
childColumns = arrayOf("statefk"),
onDelete = ForeignKey.NO_ACTION
)
]
)
data class City(
@PrimaryKey
@ColumnInfo(name = "city_id") // <<<<<<<<<< ADDED name
var id: Long = 0
) : Serializable {
@ColumnInfo(name = "city_name") //<<<<<<<<<< ADDED name
var name: String = ""
@ColumnInfo(index = true)
var statefk: Long = 0
}
状态:-
@Entity
data class State(
@PrimaryKey
@ColumnInfo(name = "state_id") // ADDED name
var id: Long = 0
) : Serializable {
@ColumnInfo(name = "state_name") // ADDED name
var name: String = ""
}
接下来是 POJO AddressWithCityWithState:-
data class AddressWithCityWithState (
@Embedded
val address: Address,
@Embedded
val city: City,
@Embedded
val state: State
)
一个合适的DAO:-
@Query("SELECT * FROM address JOIN city on address.cityfk = city.city_id JOIN state ON city.statefk = state.state_id")
fun getAllAddressesWithCityAndWithState(): List<AddressWithCityWithState>
- 由于列重命名而简化,所以 * 代替 AS 子句用于不明确的列名
使用上述: -
allDao = db.getAllDao()
var state = State()
state.name = "State1"
var stateid = allDao.insert(state)
var city = City()
city.name = "City1"
city.statefk = stateid
var cityid = allDao.insert(city)
var address = Address()
address.name = "Address1"
address.cityfk = cityid
allDao.insert(address)
for(awcws: AddressWithCityWithState in allDao.getAllAddressesWithCityAndWithState()) {
Log.d("DBINFO","${awcws.address.name}, ${awcws.city.name}, ${awcws.state.name}")
}
日志中的结果是:-
2021-11-22 07:43:28.574 D/DBINFO: Address1, City1, State1
其他工作示例(不更改列名)
无需对实体(地址、城市和州)进行任何更改。以下是其他选项的工作示例。
1-将完整地址作为单个字符串获取,所需要的只是查询,例如:-
@Query("SELECT address.name||','||city.name||','||state.name AS fullAddress FROM address JOIN city ON address.cityfk = city.id JOIN state ON city.statefk = state.id ")
fun getAddressesAsStrings(): List<String>
- 当然,下拉选择器没有太多用处,因为您无法确定数据库中的行来自何处。
2 - 具有明确列名的基本 POJO
POJO:-
data class AddressWithCityWithState(
var address_id: Long,
var address_name: String,
var city_id: Long,
var city_name: String,
var state_id: Long,
var state_name: String
)
查询:-
/*
* Returns multiple columns renamed using AS clause to disambiguate
* requires POJO with matching column names
* */
@Query("SELECT " +
"address.id AS address_id, address.name AS address_name, " +
"city.id AS city_id, city.name AS city_name, " +
"state.id AS state_id, state.name AS state_name " +
"FROM address JOIN city ON address.cityfk = city.id JOIN state ON city.statefk = state.id")
fun getAddressesWithCityAndStateViaBasicPOJO(): List<AddressWithCityWithState>
3-使用嵌入的 POJO
POJO:-
data class AddressWithCityWithStateViaEmbeds(
@Embedded
var address: Address,
@Embedded(prefix = cityPrefix)
var city: City,
@Embedded(prefix = statePrefix)
var state: State
) {
companion object {
const val cityPrefix = "city_"
const val statePrefix = "state_"
}
}
查询:-
/*
* Returns multiple columns renamed according to the prefix=? coded in the
* @Embedded annotation
*
*/
@Query("SELECT address.*, " +
"city.id AS " + AddressWithCityWithStateViaEmbeds.cityPrefix + "id," +
"city.name AS " + AddressWithCityWithStateViaEmbeds.cityPrefix + "name," +
"city.statefk AS " + AddressWithCityWithStateViaEmbeds.cityPrefix + "statefk," +
"state.id AS " + AddressWithCityWithStateViaEmbeds.statePrefix + "id," +
"state.name AS " + AddressWithCityWithStateViaEmbeds.statePrefix + "name " +
"FROM address JOIN city ON address.cityfk = city.id JOIN state ON city.statefk = state.id")
fun getAddressesWithCityAndStateViaEmbedPOJO(): List<AddressWithCityWithStateViaEmbeds>
4- POJO 与父 EMBED 和子 RELATE
POJO的:-
data class CityWithState(
@Embedded
var city: City,
@Relation(
entity = State::class,
parentColumn = "statefk",
entityColumn = "id"
)
var state: State
)
和 :-
data class AddressWithCityWithStateViaRelations(
@Embedded
var address: Address,
@Relation(
entity = City::class, /* NOTE NOT CityWithState which isn't an Entity */
parentColumn = "cityfk",
entityColumn = "id"
)
var cityWithState: CityWithState
)
和查询: -
@Transaction
@Query("SELECT * FROM address")
fun getAddressesWithCityAndStateViaRelations(): List<AddressWithCityWithStateViaRelations>
- 请注意@Tranaction 的使用,因此由 Room 构建的底层查询都在单个数据库事务中完成。
将上述内容投入使用
活动中的以下代码使用全部 4 来输出相同的结果:-
class MainActivity : AppCompatActivity() {
lateinit var db: TheDatabase
lateinit var dao: AllDao
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val TAG: String = "DBINFO"
db = TheDatabase.getInstance(this)
dao = db.getAllDao()
var state = State(1)
state.name = "State1"
val state1Id = dao.insert(state)
state.id = 2
state.name = "State2"
val state2Id = dao.insert(state)
var city = City(10)
city.name = "City1"
city.statefk = state1Id
val city1Id = dao.insert(city)
city.id = 11
city.name = "City2"
city.statefk = state2Id
val city2Id = dao.insert(city)
city.id = 12
city.name = "City3"
city.statefk = state1Id
val city3Id = dao.insert(city)
var address = Address(100)
address.name = "Address1"
address.cityfk = city1Id
dao.insert(address)
address.id = address.id + 1
address.name = "Address2"
address.cityfk = city2Id
dao.insert(address)
address.id = address.id + 1
address.name = "Address3"
address.cityfk = city3Id
for (s: String in dao.getAddressesAsStrings()) {
Log.d(TAG + "STRG", s)
}
for (awcws: AddressWithCityWithState in dao.getAddressesWithCityAndStateViaBasicPOJO()) {
Log.d(TAG + "BASICPOJO", "${awcws.address_name}, ${awcws.city_name}, ${awcws.state_name}")
}
for (awcwsve: AddressWithCityWithStateViaEmbeds in dao.getAddressesWithCityAndStateViaEmbedPOJO()) {
Log.d(TAG + "EMBEDS","${awcwsve.address.name}, ${awcwsve.city.name}, ${awcwsve.state.name}")
}
for(awcwsvr: AddressWithCityWithStateViaRelations in dao.getAddressesWithCityAndStateViaRelations()) {
Log.d(TAG + "MIXED","${awcwsvr.address.name}, ${awcwsvr.cityWithState.city.name}, ${awcwsvr.cityWithState.state.name}")
}
}
}
日志的输出是: -
2021-11-22 12:33:54.322 D/DBINFOSTRG: Address1,City1,State1
2021-11-22 12:33:54.322 D/DBINFOSTRG: Address2,City2,State2
2021-11-22 12:33:54.324 D/DBINFOBASICPOJO: Address1, City1, State1
2021-11-22 12:33:54.324 D/DBINFOBASICPOJO: Address2, City2, State2
2021-11-22 12:33:54.326 D/DBINFOEMBEDS: Address1, City1, State1
2021-11-22 12:33:54.326 D/DBINFOEMBEDS: Address2, City2, State2
2021-11-22 12:33:54.332 D/DBINFOMIXED: Address1, City1, State1
2021-11-22 12:33:54.332 D/DBINFOMIXED: Address2, City2, State2