Тип возврата для присоединения Android Room
Допустим, я хочу сделать INNER JOIN
между двумя лицами Foo
а также Bar
:
@Query("SELECT * FROM Foo INNER JOIN Bar ON Foo.bar = Bar.id")
List<FooAndBar> findAllFooAndBar();
Можно ли принудительно вернуть тип возврата, как это?
public class FooAndBar {
Foo foo;
Bar bar;
}
Когда я пытаюсь сделать это, я получаю эту ошибку:
error: Cannot figure out how to read this field from a cursor.
Я также пытался совмещать имена таблиц с именами полей, но это тоже не сработало.
Если это невозможно, как правильно составить совместимый тип возвращаемого значения, включающий все поля для обоих объектов?
5 ответов
Dao
@Query("SELECT * FROM Foo")
List<FooAndBar> findAllFooAndBar();
Учебный класс FooAndBar
public class FooAndBar {
@Embedded
Foo foo;
@Relation(parentColumn = "Foo.bar_id", entityColumn = "Bar.id")
//Relation returns a list
//Even if we only want a single Bar object ..
List<Bar> bar;
//Getter and setter...
}
Это решение, кажется, работает, но я не очень горжусь этим. Что вы думаете об этом?
Изменить: еще одно решение
Дао, я предпочитаю явно выбирать, но "*" сделает работу:)
@Query("SELECT Foo.*, Bar.* FROM Foo INNER JOIN Bar ON Foo.bar = Bar.id")
List<FooAndBar> findAllFooAndBar();
Учебный класс FooAndBar
public class FooAndBar {
@Embedded
Foo foo;
@Embedded
Bar bar;
//Getter and setter...
}
Другой вариант - просто написать новый POJO, представляющий результирующую структуру вашего запроса JOIN (который даже поддерживает переименование столбцов, чтобы избежать конфликтов):
@Dao
public interface FooBarDao {
@Query("SELECT foo.field1 AS unique1, bar.field1 AS unique2 "
+ "FROM Foo INNER JOIN Bar ON Foo.bar = Bar.id")
public List<FooBar> getFooBars();
static class FooBar {
public String unique1;
public String unique2;
}
}
Смотрите: room / accessing-data.html # query-множественные таблицы
Попробуйте так. Например, у меня есть отношения M2M (многие-ко-многим) между Product
а также Attribute
, Многие продукты имеют много атрибутов, и мне нужно получить все атрибуты по Product.id
с отсортированными записями по PRODUCTS_ATTRIBUTES.DISPLAY_ORDERING
,
|--------------| |--------------| |-----------------------|
| PRODUCT | | ATTRIBUTE | | PRODUCTS_ATTRIBUTES |
|--------------| |--------------| |-----------------------|
| _ID: Long | | _ID: Long | | _ID: Long |
| NAME: Text | | NAME: Text | | _PRODUCT_ID: Long |
|______________| |______________| | _ATTRIBUTE_ID: Long |
| DISPLAY_ORDERING: Int |
|_______________________|
Итак, модели будут как ниже:
@Entity(
tableName = "PRODUCTS",
indices = [
Index(value = arrayOf("NAME"), unique = true)
]
)
class Product {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "_ID")
var _id: Long = 0
@ColumnInfo(name = "NAME")
@SerializedName(value = "NAME")
var name: String = String()
}
@Entity(
tableName = "ATTRIBUTES",
indices = [
Index(value = arrayOf("NAME"), unique = true)
]
)
class Attribute {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "_ID")
var _id: Long = 0
@ColumnInfo(name = "NAME")
@SerializedName(value = "NAME")
var name: String = String()
}
И таблица "соединения" будет:
@Entity(
tableName = "PRODUCTS_ATTRIBUTES",
indices = [
Index(value = ["_PRODUCT_ID", "_ATTRIBUTE_ID"])
],
foreignKeys = [
ForeignKey(entity = Product::class, parentColumns = ["_ID"], childColumns = ["_PRODUCT_ID"]),
ForeignKey(entity = Attribute::class, parentColumns = ["_ID"], childColumns = ["_ATTRIBUTE_ID"])
]
)
class ProductAttribute {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "_ID")
var _id: Long = 0
@ColumnInfo(name = "_PRODUCT_ID")
var _productId: Long = 0
@ColumnInfo(name = "_ATTRIBUTE_ID")
var _attributeId: Long = 0
@ColumnInfo(name = "DISPLAY_ORDERING")
var displayOrdering: Int = 0
}
В, AttributeDAO
, чтобы получить все атрибуты на основе Product._ID
Вы можете сделать что-то вроде ниже:
@Dao
interface AttributeDAO {
@Query("SELECT ATTRIBUTES.* FROM ATTRIBUTES INNER JOIN PRODUCTS_ATTRIBUTES ON PRODUCTS_ATTRIBUTES._ATTRIBUTE_ID = ATTRIBUTES._ID INNER JOIN PRODUCTS ON PRODUCTS._ID = PRODUCTS_ATTRIBUTES._PRODUCT_ID WHERE PRODUCTS._ID = :productId ORDER BY PRODUCTS_ATTRIBUTES.DISPLAY_ORDERING ASC")
fun getAttributesByProductId(productId: Long): LiveData<List<Attribute>>
}
Если у вас есть какие-либо вопросы, пожалуйста, скажите мне.
Можно ли принудительно вернуть тип возврата, как это?
Ты можешь попробовать @Embedded
аннотации на foo
а также bar
, Это скажет Room, чтобы попытаться взять столбцы из вашего запроса и вылить их в foo
а также bar
экземпляров. Я пробовал это только с объектами, но документы указывают, что он должен работать и с POJO.
Однако это может не сработать, если в ваших двух таблицах есть столбцы с одинаковыми именами.
Это моя таблица еды
@Entity(tableName = "_food_table")
data class Food(@PrimaryKey(autoGenerate = false)
@ColumnInfo(name = "_food_id")
var id: Int = 0,
@ColumnInfo(name = "_name")
var name: String? = "")
Это моя корзина стола и модель класса (Food Cart)
@Entity(tableName = "_client_cart_table")
data class CartItem(
@PrimaryKey(autoGenerate = false)
@ColumnInfo(name = "_food_id")
var foodId: Int? = 0,
@Embedded(prefix = "_food")
var food: Food? = null,
@ColumnInfo(name = "_branch_id")
var branchId: Int = 0)
Примечание: здесь мы видим столбец _food_id в двух таблицах. Это вызовет ошибку времени компиляции. Начиная с @Embedded doc, вы должны использовать префикс, чтобы различать их.
Внутри дао
@Query("select * from _client_cart_table inner join _food_table on _client_cart_table._food_id = _food_table._food_id where _client_cart_table._branch_id = :branchId")
fun getCarts(branchId: Int) : LiveData<List<CartItem>>
Этот запрос вернет данные как это
CartItem(foodId=5, food=Food(id=5, name=Black Coffee), branchId=1)
Я сделал это в моем проекте. Так что попробуйте. Удачного кодирования