Android Room连接的返回类型

时间:2017-07-12 14:04:36

标签: android android-room android-architecture-components

我想说我想在两个实体INNER JOINFoo之间进行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 个答案:

答案 0 :(得分:38)

@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...
}

这个解决方案似乎有效,但我并不为此感到自豪。 你觉得怎么样?

编辑:另一种解决方案

道,我更愿意明确选择但是&#34; *&#34;将完成这项工作:)

@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...
}

答案 1 :(得分:7)

试试这种方式。 例如,我在ProductAttribute之间存在M2M(多对多)关系。许多产品有很多属性,我需要按Product.id获取所有属性,并按PRODUCTS_ATTRIBUTES.DISPLAY_ORDERING排序记录。< / p>

|--------------|  |--------------|  |-----------------------|
| 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>>

}

如果您有任何疑问,请告诉我。

答案 2 :(得分:4)

另一种选择是编写一个新的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-multiple-tables

答案 3 :(得分:2)

  

是否可以强制这样的返回类型?

您可以在@Embeddedfoo上尝试bar注释。这将告诉Room尝试从您的查询中获取列并将它们转移到foobar个实例中。我只对实体尝试了这个,但是文档表明它也应该与POJO一起使用。

但是,如果您的两个表具有相同名称的列,则这可能无法正常工作。

答案 4 :(得分:0)

这是我的食物表

@Entity(tableName = "_food_table")
data class Food(@PrimaryKey(autoGenerate = false)
            @ColumnInfo(name = "_food_id")
            var id: Int = 0,
            @ColumnInfo(name = "_name")
            var name: String? = "")

这是我的购物车表和模型类(食物购物车)

@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)

我已经在我的项目中做到了。所以试试吧。编码愉快

相关问题