Тип возврата для присоединения Android Room

Допустим, я хочу сделать 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.

Я также пытался совмещать имена таблиц с именами полей, но это тоже не сработало.

Если это невозможно, как правильно составить совместимый тип возвращаемого значения, включающий все поля для обоих объектов?

5 ответов

Dao

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

Другой вариант - просто написать новый 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-множественные таблицы

Попробуйте так. Например, у меня есть отношения M2M (многие-ко-многим) между Product а также Attribute, Многие продукты имеют много атрибутов, и мне нужно получить все атрибуты по Product.id с отсортированными записями по 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>>

}

Если у вас есть какие-либо вопросы, пожалуйста, скажите мне.

Можно ли принудительно вернуть тип возврата, как это?

Ты можешь попробовать @Embedded аннотации на foo а также bar, Это скажет Room, чтобы попытаться взять столбцы из вашего запроса и вылить их в foo а также bar экземпляров. Я пробовал это только с объектами, но документы указывают, что он должен работать и с POJO.

Однако это может не сработать, если в ваших двух таблицах есть столбцы с одинаковыми именами.

Это моя таблица еды

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

Это моя корзина стола и модель класса (Food Cart)

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

Я сделал это в моем проекте. Так что попробуйте. Удачного кодирования

Другие вопросы по тегам