Android Room连接的返回类型

pqv*_*vst 46 android android-room android-architecture-components

比方说,我想要做的INNER JOIN两个实体之间FooBar:

@Query("SELECT * FROM Foo INNER JOIN Bar ON Foo.bar = Bar.id")
List<FooAndBar> findAllFooAndBar();
Run Code Online (Sandbox Code Playgroud)

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

public class FooAndBar {
    Foo foo;
    Bar bar;
}
Run Code Online (Sandbox Code Playgroud)

当我尝试这样做时,我收到此错误:

error: Cannot figure out how to read this field from a cursor.
Run Code Online (Sandbox Code Playgroud)

我也尝试使表名称别名来匹配字段名称,但这也不起作用.

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

小智 47

@Query("SELECT * FROM Foo")
List<FooAndBar> findAllFooAndBar();
Run Code Online (Sandbox Code Playgroud)

FooAndBar

public class FooAndBar {
    @Embedded
    Foo foo;

    @Relation(parentColumn =  "Foo.bar_id", entityColumn = "Bar.id")
    //Relation is designed to return a list
    List<Bar> bar;
    // If we are sure it returns only one entry
    // Bar bar;

    //Getter and setter...
}
Run Code Online (Sandbox Code Playgroud)

这个解决方案似乎有效,但我并不为此感到自豪.你怎么看待这件事?

编辑:另一种解决方案

Dao,我更喜欢明确选择,但"*"会做的工作:)

@Query("SELECT Foo.*, Bar.* FROM Foo INNER JOIN Bar ON Foo.bar = Bar.id")
List<FooAndBar> findAllFooAndBar();
Run Code Online (Sandbox Code Playgroud)

FooAndBar

public class FooAndBar {
    @Embedded
    Foo foo;

    @Embedded
    Bar bar;

    //Getter and setter...
}
Run Code Online (Sandbox Code Playgroud)

  • 第二个解决方案导致"多个字段具有相同的columnName"编译错误,然后实体具有名为same:id的PK属性 (12认同)
  • 第二种解决方案实际起作用吗?Coz我收到“无法弄清楚如何转换游标...”错误。另外,我正在使用`@Embedded(prefix =“ foo _”)`和`@Embedded(prefix =“ bar _”)` (3认同)

dph*_*ans 7

试试这种方式.例如,我有之间M2M(许多一对多)的关系ProductAttribute.许多产品都有很多属性,我需要通过排序记录来获取所有属性.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 |
                                    |_______________________|
Run Code Online (Sandbox Code Playgroud)

所以,模型如下:

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

}
Run Code Online (Sandbox Code Playgroud)

而"加入"表将是:

@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

}
Run Code Online (Sandbox Code Playgroud)

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

}
Run Code Online (Sandbox Code Playgroud)

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


Aja*_*les 5

另一个选择是只编写一个新的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;
   }
}    
Run Code Online (Sandbox Code Playgroud)

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

  • 当字段具有相同的名称时,这仅适用于它们的别名。 (2认同)

Com*_*are 3

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

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

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

  • @pqvst:“我应该如何干净地构造一个兼容的返回类型,其中包括两个实体的所有字段?” -- 选择 `foo` 或 `bar` 为 `@Embedded` 并将其余字段直接放入 `FooAndBar` 中,或者将所有字段直接放入 `FooAndBar` 中。在 SQL 中使用“AS”重命名结果集中的重复列,并根据需要使用“@ColumnInfo”将这些“AS”重命名的列映射到您想要的字段。 (2认同)