android - studio - room insert list
Tipo de devolución para las combinaciones de Android Room (5)
¿Es posible forzar un tipo de retorno como este?
Puedes probar @Embedded
anotaciones @Embedded
en foo
y bar
. Eso le dirá a Room que intente tomar las columnas de su consulta y verterlas en instancias foo
y bar
. Solo he intentado esto con entidades, pero los documentos indican que también debería funcionar con POJOs.
Sin embargo, esto puede no funcionar bien si sus dos tablas tienen columnas con el mismo nombre.
Digamos que quiero hacer una INNER JOIN
entre dos entidades Foo
y Bar
:
@Query("SELECT * FROM Foo INNER JOIN Bar ON Foo.bar = Bar.id")
List<FooAndBar> findAllFooAndBar();
¿Es posible forzar un tipo de retorno como este?
public class FooAndBar {
Foo foo;
Bar bar;
}
Cuando trato de hacer eso, me sale este error:
error: Cannot figure out how to read this field from a cursor.
También he intentado aliasar los nombres de las tablas para que coincidan con los nombres de los campos, pero eso tampoco funcionó.
Si esto no es posible, ¿cómo debo construir limpiamente un tipo de retorno compatible que incluya todos los campos para ambas entidades?
Dao
@Query("SELECT * FROM Foo")
List<FooAndBar> findAllFooAndBar();
Clase 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...
}
Esta solución parece funcionar, pero no estoy muy orgullosa de ello. ¿Qué piensa usted al respecto?
Edit: Otra solución
Dao, prefiero seleccionar explícitamente pero "*" hará el trabajo :)
@Query("SELECT Foo.*, Bar.* FROM Foo INNER JOIN Bar ON Foo.bar = Bar.id")
List<FooAndBar> findAllFooAndBar();
Clase FooAndBar
public class FooAndBar {
@Embedded
Foo foo;
@Embedded
Bar bar;
//Getter and setter...
}
Esta es mi mesa de comida
@Entity(tableName = "_food_table")
data class Food(@PrimaryKey(autoGenerate = false)
@ColumnInfo(name = "_food_id")
var id: Int = 0,
@ColumnInfo(name = "_name")
var name: String? = "")
Esta es mi tabla de carro y modelo de clase (Carrito de comida)
@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)
Nota: Aquí vemos la columna _food_id en dos tablas. Se lanzará error de tiempo de compilación. Desde @Embedded doc, tienes que usar el prefijo para diferenciarlos.
Dentro de dao
@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>>
Esta consulta devolverá datos como este.
CartItem(foodId=5, food=Food(id=5, name=Black Coffee), branchId=1)
He hecho esto en mi proyecto. Así que inténtalo. Feliz codificacion
Otra opción es simplemente escribir un nuevo POJO que represente la estructura resultante de su consulta JOIN (que incluso admite el cambio de nombre de columnas para evitar conflictos):
@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;
}
}
Prueba de esta manera Por ejemplo, tengo relaciones M2M (muchos a muchos) entre Product
y Attribute
. Muchos Productos tienen muchos Atributos y necesito obtener todos los Atributos por Product.id
con registros ordenados por 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 |
|_______________________|
Por lo tanto, los modelos serán como a continuación:
@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()
}
Y la tabla de "unirse" será:
@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
}
En, AttributeDAO
, para obtener todos los atributos basados en Product._ID
, puede hacer algo como a continuación:
@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>>
}
Si tiene alguna pregunta, por favor dígame.