房间不会自动生成主键

9
我对API响应有以下模型:
@Entity(tableName = TABLE_NAME)
class WeatherEntry {

    @PrimaryKey(autoGenerate = true)
    var wID: Long? = null

    @SerializedName("dt")
    @ColumnInfo(name = COLUMN_DATE)
    var date: String = ""

    @SerializedName("city")
    @Embedded(prefix = "location_")
    var location: Location? = null

    @SerializedName("main")
    @Embedded(prefix = "main_")
    var main: Main? = null

    @SerializedName("weather")
    @TypeConverters(Converters::class)
    @Embedded(prefix = "weather_")
    var weather: ArrayList<Weather>? = null

    @SerializedName("wind")
    @Embedded(prefix = "wind_")
    var wind: Wind? = null

}

天气报告 从本地或远程数据源获取数据,我将forceRemote设置为true,否则一开始就不会显示任何数据。

class WeatherRepository @Inject constructor(@Local var localDataSource: WeatherDataSource, @Remote var remoteDataSource: WeatherDataSource) :
    WeatherDataSource {

   private var caches: MutableList<WeatherEntry> = mutableListOf()
   override fun getWeatherEntries(location: String, forceRemote: Boolean): Flowable<MutableList<WeatherEntry>> {

        if (forceRemote) {
            return refreshData(location)
        } else {
            return if (caches.isNotEmpty()) {
                // if cache is available, return it immediately
                Flowable.just(caches)
            } else {
                // else return data from local storage
                localDataSource.getWeatherEntries(location, false)
                    .take(1)
                    .flatMap(({ Flowable.fromIterable(it) }))
                    .doOnNext { question -> caches.add(question) }
                    .toList()
                    .toFlowable()
                    .filter({ list -> !list.isEmpty() })
                    .switchIfEmpty(refreshData(location)) // If local data is empty, fetch from remote source instead.
            }
        }
    }

    /**
     * Fetches data from remote source.
     * Save it into both local database and cache.
     *
     * @return the Flowable of newly fetched data.
     */
    private fun refreshData(location: String): Flowable<MutableList<WeatherEntry>> {

        return remoteDataSource.getWeatherEntries(location,true).doOnNext({

            // Clear cache
            caches.clear()
            // Clear data in local storage
            localDataSource.deleteAllWeatherEntries()
        }).flatMap(({ Flowable.fromIterable(it) })).doOnNext({ entry ->
            caches.add(entry)
            localDataSource.insertWeatherEntry(entry)
        }).toList().toFlowable()
    }

本地数据源
class WeatherLocalDataSource @Inject constructor(private var weatherDao: WeatherDao): WeatherDataSource {

    override fun insertWeatherEntry(weatherEntry: WeatherEntry) {
        return weatherDao.insert(weatherEntry)
    }

    ...
}

远程数据源 这个肯定有效,因为我从API中获取了所有信息。

class WeatherRemoteDataSource @Inject constructor(var weatherService: WeatherService) :
    WeatherDataSource {

    override fun getWeatherEntries(location: String, forceRemote: Boolean): Flowable<MutableList<WeatherEntry>> {
        return weatherService.getForecast(
            location,
            "json",
            "metric",
            BuildConfig.OPEN_WEATHER_MAP_API_KEY
        ).map(WeatherForecastResponse::weatherEntries)
    }
}

DAO

@Dao
interface WeatherDao {

    ...

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insert(weatherEntry: WeatherEntry)
}

数据库

@Database(
    entities = [(WeatherEntry::class)],
    version = 1
)
abstract class WeatherDatabase : RoomDatabase() {

    abstract fun weatherDao(): WeatherDao
}

所有其他字段都正常工作,但是wID始终为null。我的实现有什么问题吗?
我已经尝试将其默认值更改为0并将类型更改为Int,但也不起作用。
3个回答

8
尝试使id字段为非空:
 @PrimaryKey(autoGenerate = true)
    var wID: Long = 0
编辑: 我在示例代码中找到了这个。 你可以让你的@Insert方法返回插入行对象的id,这样你就可以这样做:

在你的Dao中:

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(weatherEntry: WeatherEntry) : Long

在您的刷新数据方法中:
private fun refreshData(location: String): Flowable<MutableList<WeatherEntry>> {

        return remoteDataSource.getWeatherEntries(location,true).doOnNext({

            // Clear cache
            caches.clear()
            // Clear data in local storage
            localDataSource.deleteAllWeatherEntries()
        }).flatMap(({ Flowable.fromIterable(it) })).doOnNext({ entry ->

            val entryID = localDataSource.insertWeatherEntry(entry)
            entry.wID = entryID
            caches.add(entry)
        }).toList().toFlowable()
    }

1
当你这样做时,值不能为null,它现在是什么? - Levi Moreira
1
你是如何测试的? - Levi Moreira
3
我询问这个问题是因为在你把对象插入数据库之前,id 的值将为 0。根据文档,“如果字段类型为 long 或 int(或其 TypeConverter 将其转换为 long 或 int),Insert 方法在插入项时将 0 视为未设置。” - Levi Moreira
我从API中获取它,然后在RecyclerView中显示一些项目字段(包括wID),但也许这就是问题的原因。我会在晚上尝试修复它并告诉你是否是这个问题。谢谢! - niclaszll
1
没有API中的wID字段,所以我没有在它上面放置@SerializedName。但也许这是个好主意,只需选择一个不需要的字段并用autogenerate覆盖它 :D - niclaszll
显示剩余6条评论

4

阅读https://developer.android.com/reference/androidx/room/PrimaryKey?hl=en#autoGenerate(),你将得到答案。

public boolean autoGenerate ()
Set to true to let SQLite generate the unique id.

When set to true, the SQLite type affinity for the field should be INTEGER.

If the field type is long or int (or its TypeConverter converts it to a long or int), Insert methods treat 0 as not-set while inserting the item.

If the field's type is Integer or Long (or its TypeConverter converts it to an Integer or a Long), Insert methods treat null as not-set while inserting the item.

1

解决我的问题的方法是将主键的类型从“long”更改为“Long”(Java)

@PrimaryKey(autoGenerate = true) @ColumnInfo(name = "task_id") private Long taskID;


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接