64

假设我想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.

我还尝试为表名起别名以匹配字段名,但这也不起作用。

如果这是不可能的,我应该如何干净地构造一个兼容的返回类型,其中包括两个实体的所有字段?

4

5 回答 5

70

@Query("SELECT * FROM Foo")
List<FooAndBar> findAllFooAndBar();

班级FooAndBar

public class FooAndBar {
    @Embedded
    Foo foo;

    @Relation(parentColumn =  "Foo.bar_id", entityColumn = "Bar.id")
    List<Bar> bar;
    // If we are sure it returns only one entry
    // 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...
}

编辑:从版本 2.2.0-alpha01 开始,房间 @Relation 注释可以管理一对一的关系

于 2017-07-26T12:38:32.697 回答
17

另一种选择是只编写一个新的 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;
   }
}    

请参阅:房间/accessing-data.html#query-multiple-tables

于 2017-12-28T20:18:17.767 回答
13

试试这个方法。Product例如,我在和之间有 M2M(多对多)关系Attribute。许多产品有很多属性,我需要通过排序记录来获取所有属性Product.idPRODUCTS_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>>

}

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

于 2018-05-04T13:10:02.387 回答
3

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

您可以在和上尝试@Embedded注释。这将告诉 Room 尝试从查询中获取列并将它们倒入实例中。我只对实体进行了尝试,但文档表明它也应该与 POJO 一起使用。foobarfoobar

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

于 2017-07-12T14:32:16.350 回答
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)

我在我的项目中做到了这一点。所以试试吧。快乐编码

于 2018-09-20T05:37:25.293 回答