web-dev-qa-db-ja.com

Androidルーム参加の戻りタイプ

2つのエンティティFooBarの間でINNER JOINを実行するとします。

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

また、フィールド名と一致するようにテーブル名のエイリアスを作成しようとしましたが、それも機能しませんでした。

これが不可能な場合、両方のエンティティのすべてのフィールドを含む互換性のある戻り値型をどのようにきれいに構築する必要がありますか?

44
pqvst

ダオ

@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...
}
43
Gaëtan S

この方法を試してください。たとえば、ProductAttributeの間にM2M(多対多)関係があります。多くの製品には多くの属性があり、すべてを取得する必要があります属性 by Product.id by 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>>

}

ご質問があれば、教えてください。

7
dphans

もう1つのオプションは、JOINクエリの結果の構造を表す新しいPOJOを記述することです(衝突を避けるために列名の変更もサポートします)。

@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

4
AjahnCharles

このような戻り値の型を強制することは可能ですか?

fooおよびbar@Embedded注釈を試すことができます。これにより、Roomにクエリから列を取得し、fooおよびbarインスタンスにそれらを注ぐように指示します。エンティティでこれを試しただけですが、ドキュメントでは、POJOでも同様に機能するはずであることが示されています。

ただし、2つのテーブルに同じ名前の列がある場合、これはうまく機能しない可能性があります。

2
CommonsWare

これは私の食卓です

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

注:ここでは、2つのテーブルに_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)

私は自分のプロジェクトでこれを行いました。試してみてください。ハッピーコーディング

0
Shaon