如何向Room数据库添加嵌套和关联。

huangapple go评论72阅读模式
英文:

How to add Embedded and Relation to room database

问题

你可以使用以下查询来获取所需的结果:

@Transaction
@Query("SELECT * FROM SPECIAL")
fun getAllSpecialsWithItemsAndFavourites(): List<SomeClass>

这个查询将选择所有的特殊项目,并将它们映射到你的期望类 SomeClass 中,包括特殊项目的详细信息和用户是否将其标记为收藏。

至于数据库结构的改进,当前的结构看起来已经很合理了,特别是考虑到你的用例是一个演示应用,只有一个用户。如果未来需要扩展功能,可能需要进一步优化数据库结构,但当前的设计足以满足你的需求。

英文:

Let's say I have these tables :

Table - User

>Stores the users

@Entity(
    tableName = &quot;USER&quot;
)
data class User(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = &quot;user_id&quot;)
    val id: Int,

    @ColumnInfo(name = &quot;user_name&quot;)
    val name: String
)

Table - Item

>Store the items it's like a product

@Entity(
    tableName = &quot;ITEM&quot;
)
data class Item(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = &quot;item_id&quot;)
    val id: Int,

    @ColumnInfo(name = &quot;item_name&quot;)
    val name: String,

    @ColumnInfo(name = &quot;item_description&quot;)
    val description: String
)

Table - Special

>Store an speciality for product 1 Special needs a Product to exist

@Entity(
    tableName = &quot;SPECIAL&quot;,
    foreignKeys = [ForeignKey(
        entity = Item::class,
        parentColumns = [&quot;item_id&quot;],
        childColumns = [&quot;special_item_id&quot;]
    )]
)
data class Special(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = &quot;special_id&quot;)
    val id: Int,

    @ColumnInfo(name = &quot;special_item_id&quot;)
    val coupon_product_id: Int,

    @ColumnInfo(name = &quot;special_name&quot;)
    val name: String,

    @ColumnInfo(name = &quot;special_description&quot;)
    val description: String

)

Table -- Favourite

>Stores the favourite Specials from an user

@Entity(
    tableName = &quot;TB_FAVOURITE&quot;,
    foreignKeys = [ForeignKey(
        entity = User::class,
        parentColumns = [&quot;user_id&quot;],
        childColumns = [&quot;favourite_user_id&quot;]
    ), ForeignKey(
        entity = Special::class,
        parentColumns = [&quot;special_id&quot;],
        childColumns = [&quot;favourite_special_id&quot;]
    )]
)
data class Favourite(
    @PrimaryKey
    @ColumnInfo(name = &quot;favourite_user_id&quot;)
    val id: Int,

    @ColumnInfo(name = &quot;favourite_special_id&quot;)
    val specialId: Int

)

My question is, how can I make a query to select all the Specials and then creating like a class that stores if it's favourite of the user or not. It's one user app for the moment, it's for a demo app. So, user will always be the same so I can hardcode the findById and send the id of the user.

The goal

Is to get a result of a query as List<SomeClass> that contains :

  1. All of the Specials
  2. In the SomeClass should contain the Item of the Special inside
  3. A flag to know if it's favourite for that driver or not

The thing is I want to be able to map the result of the room database to my desired object, so I guess the query is more important than the mapper, I know how to do the mapper.

Note that I'm using an assets/database/mydb.db file to start the database I don't know if it matters, so I do not know how would work using Embedded and Relation here

How would be the query to do that? Is there any improvement of the structure of the db to make it easier?

答案1

得分: 3

我认为查询比映射器更重要,我知道如何进行映射。

好吧,查询取决于您想要获得的结果的结构。
我认为在这种情况下,@Relation无法帮助(表之间的关系对于它来说太复杂了),所以我建议使用带有JOIN的自定义查询。

我的建议是添加一个具有您需要获得的结构的类(尽管您可以更改它):

data class SpecialityDetails( 
    @Embedded
    val special: Special, 
    @Embedded
    val item: Item,
    val favourite: Boolean
)

并在DAO中添加下一个方法(据我了解,您可以在此方法中传递userId):

@Query("SELECT *, CASE WHEN tb_favourite.favourite_user_id IS NULL THEN 0 ELSE 1 END AS favourite FROM special 
INNER JOIN ITEM ON special.special_item_id = ITEM.item_id 
LEFT JOIN tb_favourite ON special.special_id = tb_favourite.favourite_special_id 
AND tb_favourite.favourite_user_id = :userId")

fun getSpecials(userId: Int): List<SpecialityDetails>

由于SpecialityDetails包含查询中的所有字段,Room将为您执行映射。

更新
为您的Favourite类使用复合主键:

@Entity(
    tableName = "TB_FAVOURITE",
    primaryKeys = ["favourite_user_id", "favourite_special_id"],
    foreignKeys = [ForeignKey(
        entity = User::class,
        parentColumns = ["user_id"],
        childColumns = ["favourite_user_id"]
    ), ForeignKey(
        entity = Special::class,
        parentColumns = ["special_id"],
        childColumns = ["favourite_special_id"]
    )]
)
data class Favourite(
    @ColumnInfo(name = "favourite_user_id")
    val id: Int,

    @ColumnInfo(name = "favourite_special_id")
    val specialId: Int
)
英文:

> I guess the query is more important than the mapper, I know how to do the mapper.

Well, query depends on the structure of the result you want to get.
I don't think @Relation could help in that case (relations between tables are too complicated for that), so I suggest to use custom query with JOINs.

My suggestion is to add some class with structure you need to get (though you can change it):

data class SpecialityDetails( 
    @Embedded
    val special: Special, 
    @Embedded
    val item: Item,
    val favourite: Boolean
)

And in DAO add next method (as I've understood you can pass userId in this method):

@Query(&quot;select *, CASE WHEN tb_favourite.favourite_user_id is null THEN 0 else 1 END as favourite from special 
INNER JOIN ITEM ON special.special_item_id = ITEM.item_id 
LEFT JOIN tb_favourite ON special.special_id = tb_favourite.favourite_special_id 
AND tb_favourite.favourite_user_id = :userId&quot;)

fun getSpecials(userId: Int): List&lt;SpecialityDetails&gt;

Room will do mapping for you since SpecialityDetails includes all fields that are in the query.

Update
Use composite primary key for your Favourite class

@Entity(
    tableName = &quot;TB_FAVOURITE&quot;,
    primaryKeys = arrayOf(&quot;favourite_user_id&quot;, &quot;favourite_special_id&quot;),
    foreignKeys = [ForeignKey(
        entity = User::class,
        parentColumns = [&quot;user_id&quot;],
        childColumns = [&quot;favourite_user_id&quot;]
    ), ForeignKey(
        entity = Special::class,
        parentColumns = [&quot;special_id&quot;],
        childColumns = [&quot;favourite_special_id&quot;]
    )]
)
data class Favourite(
    @ColumnInfo(name = &quot;favourite_user_id&quot;)
    val id: Int,

    @ColumnInfo(name = &quot;favourite_special_id&quot;)
    val specialId: Int

)

huangapple
  • 本文由 发表于 2020年8月13日 02:39:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/63382855.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定