【问题标题】:ROOM Single Database Multiple Entities, Insert Query for different TablesROOM 单库多实体,不同表插入查询
【发布时间】:2020-09-22 23:17:34
【问题描述】:

我有一个小问题,我对如何将对象插入不同的实体感到困惑。 我尝试了一种解决方法:

@Query("INSERT INTO card_table VALUES(:id, :pid, :question, :answer, :type, :completed)")
    suspend fun insertCard(id: UUID, pid: UUID, question: String, answer: String, type: CardType, completed: Boolean)

然而,这并没有奏效。

我的问题是,如何将一个对象插入到具有单个数据库的不同实体表中。

注意 -> insert() 查询用于将牌组插入到牌组表中。该问题与 card_table 有关,因为我不确定如何引用它。

谢谢

数据库


    @Insert(onConflict = OnConflictStrategy.ABORT)
    suspend fun insert(deck: Deck)

    @Insert
    suspend fun insertCard(card: FlashCard)

@Database(entities = [Deck::class, FlashCard::class], version = 8, exportSchema = false)
@TypeConverters(DeckTypeConverters::class)
abstract class FlashCardDB : RoomDatabase() {

    abstract fun DeckDAO(): DeckDAO

    companion object {
        private var INSTANCE: FlashCardDB? = null

        fun getDatabase(context: Context, scope: CoroutineScope): FlashCardDB {
            val tmpInstance = INSTANCE

            if (tmpInstance != null) return tmpInstance

            synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    FlashCardDB::class.java,
                    "flash_cards_database"
                ).build() //.fallbackToDestructiveMigration() will causes users to loose data during migrations (use only for testing purposes)
                INSTANCE = instance
                return instance
            }
       

表格

@Entity(tableName = "deck_table")
@Parcelize
data class Deck(
    @PrimaryKey @ColumnInfo(name = "id") val id: UUID = UUID.randomUUID(),
    @ColumnInfo(name = "title") var title: String,
    @ColumnInfo(name = "date") var date: Calendar,
    @ColumnInfo(name = "completed") var completed: Boolean
) : Parcelable {


@Entity(tableName = "card_table")
@Parcelize
data class FlashCard(
    @PrimaryKey @ColumnInfo(name = "id") val id: UUID = UUID.randomUUID(),
    @ColumnInfo(name = "parent_id") var pid: UUID,
    @ColumnInfo(name = "question") var question: String,
    @ColumnInfo(name = "answer") var answer: String,
    @ColumnInfo(name = "type") var type: CardType,
    @ColumnInfo(name = "completed") var completed: Boolean)
    : Parcelable {
}

【问题讨论】:

    标签: android sqlite kotlin android-sqlite android-room


    【解决方案1】:

    我的问题是,如何使用单个数据库将对象插入到不同的实体表中

    • 要插入对象,您需要将带有@Insert 的方法放入带有@Dao 的接口或抽象类中
    • 当您构建项目时,Room 将生成您的@Dao-interface 的实现。这将是普通类,但用 Java 编写(对于DeckDAO 接口生成的类将是DeckDAO_Impl.java)。此外,Room 将实现@Insert-方法(因为您在此方法中告诉您要插入什么对象,并且 Room 知道其对应表的名称)。假设(简单地说)此方法的实现将执行查询insert into _tableName_ values (...)。
    @Insert
    suspend fun insert(deck: Deck) <-- Room will generate implementation "insert into deck_table values (..."
    
    @Insert
    suspend fun insert(card: FlashCard) <-- Room will generate implementation "insert into card_table values (..."
    
    • 要访问这个实现类的方法,您应该将您的 dao 接口放在扩展 Database 的抽象类中。构建后 Room 将为您实现这个抽象类,您可以在示例中调用方法 insert,只需:
    FlashCardDB.getDatabase().DeckDAO().insert(deck)
    

    或

    FlashCardDB.getDatabase().DeckDAO().insert(card)
    
    • 不必为每个实体创建单独的 dao 接口。理论上,您可以将单个 dao 接口与所有插入/删除/更新/查询方法一起使用。然后,您只需通过单个 FlashCardDB.getDatabase().DeckDAO() 端点访问所有这些方法。您可以在其中放置 10 个具有相同 insert 名称的插入方法,但它们应该因参数类型而异(这只是一个方法重载),或者您可以使用不同的方法名称以清楚起见。

    • 尽管在实践中(以及在大多数教程中),为了方便起见,不同实体的插入-删除-更新-查询方法被放置在不同的 dao 接口中。为此,您应该将所有这些 dao 接口放入数据库类。比方说:

    abstract class FlashCardDB : RoomDatabase() {
    
        abstract fun deckDAO(): DeckDAO
        abstract fun cardDAO(): CardDAO
    

    所以决定权在你。

    【讨论】:

      【解决方案2】:

      如果我没有正确回答您的问题,您想将卡片数据插入数据库吗?您需要做的是为每个数据库模型设置一个DAO。所以你的 Card 数据库模型会有自己的DAO:

      @Dao
      public abstract class CardDao {
          @Insert
          fun insert(card: Card)
      }
      
      @Database(entities = [Deck::class, FlashCard::class], version = 8, exportSchema = false)
      @TypeConverters(DeckTypeConverters::class)
      abstract class FlashCardDB : RoomDatabase() {
      
          abstract fun deckDao(): DeckDao
          abstract fun cardDao(): CardDao
      ...
      

      如果这回答了您的问题,请告诉我。

      【讨论】:

      • 哦,我明白了,但是,我使用的 DAO(来自 Google CodeLabs)使用了一个接口。那么我会使用两个接口吗?以及每个接口如何知道要插入哪个表
      • 嗯。您可以使用接口或抽象类。对于第二个问题,Room 使用 @Entity 注释中的 tableName 字段来确定要插入哪个表。
      • 但是接口如何理解它指的是哪个表。因为只有@Dao 会被应用?还是按时间顺序排列的事情
      • 不,它不是按时间顺序排列的。它使用tableName 字段(如果指定)或类名(如果未指定)在 SQLite 数据库中创建表。哦好的。我想我现在明白你的问题了。我之前在您原来的问题中没有看到这一行:@Insert suspend fun insertCard(card: FlashCard)。将FlashCard 实体插入数据库时​​出现什么错误?
      • 我复制了我为 cardDao 接口工作的内容。但是,它仍然不起作用。我假设的是,界面不知道我指的是哪个表。
      猜你喜欢
      • 1970-01-01
      • 2017-11-23
      • 1970-01-01
      • 2020-05-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-31
      相关资源
      最近更新 更多