首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >房间数据库中的TypeConverters问题

问房间数据库中的TypeConverters问题
EN

Stack Overflow用户
提问于 2022-11-10 06:00:46
回答 3查看 52关注 0票数 1

我试图在Android (Kotlin)中使用类型转换器,所以我使用了类型转换器类,但是我感到困惑,就像云中一样,我有一个变量,所以我返回了它,但是

代码语言:javascript
复制
@Entity(tableName = "WeatherDb")
data class WeatherDTO(
    val base: String,
    val clouds: Clouds,
    val cod: Int,
    val coord: Coord,
    val dt: Int,
    @PrimaryKey(autoGenerate = true)
    val id: Int,
    val main: Main,
    val name: String,
    val sys: Sys,
    val timezone: Int,
    val visibility: Int,
    val weather: List<Weather>,
    val wind: Wind
)

class TypeConverters {
    @TypeConverter
    fun fromCloudsToDouble(clouds: Clouds): Int {
        return clouds.all
    }

    fun fromCoordToDouble(coord: Coord): Double {

    }
}

在coord类中,这里有多个不同的数据类型,如何隐藏这一点?

代码语言:javascript
复制
data class Main(
    val feels_like: Double,
    val grnd_level: Int,
    val humidity: Int,
    val pressure: Int,
    val sea_level: Int,
    val temp: Double,
    val temp_max: Double,
    val temp_min: Double
)

Clouds.kt

代码语言:javascript
复制
data class Clouds(
    val all: Int
)

Coord.kt

代码语言:javascript
复制
data class Coord(
    val lat: Double,
    val lon: Double
)

Main.kt

代码语言:javascript
复制
data class Main(
    val feels_like: Double,
    val grnd_level: Int,
    val humidity: Int,
    val pressure: Int,
    val sea_level: Int,
    val temp: Double,
    val temp_max: Double,
    val temp_min: Double
)

Sys.kt

代码语言:javascript
复制
data class Sys(
    val country: String,
    val id: Int,
    val sunrise: Int,
    val sunset: Int,
    val type: Int
)

Weather.kt

代码语言:javascript
复制
data class Weather(
    val description: String,
    val icon: String,
    val id: Int,
    val main: String
)

Wind.kt

代码语言:javascript
复制
data class Wind(
    val deg: Int,
    val gust: Double,
    val speed: Double
)

WeatherViewModel.kt

代码语言:javascript
复制
@HiltViewModel
class WeatherViewModel @Inject constructor(
    private val repo:WeatherRepository,
    private val application: Application,
    private val WeatherDb:WeatherDB,
    private val fusedLocationProviderClient: FusedLocationProviderClient
) :ViewModel(){

    private val _resp = MutableLiveData<WeatherDTO>()
    val weatherResp:LiveData<WeatherDTO>
    get() = _resp



    private val _cord = MutableLiveData<Coord>()
    val cord:LiveData<Coord>
        get() = _cord

    var locality:String = ""

   fun getWeather(latitude:Double,longitude:Double) =
        viewModelScope.launch {
            repo.getWeather(latitude,longitude).let { response->
                if(response.isSuccessful){
                    Log.d("response","${response.body()}")
                    WeatherDb.WeatherDao().insertWeather(response.body()!!)
                    _resp.postValue(response.body())
                }else{
                    Log.d("Weather Error","getWeather Error Response: ${response.message()}")
                }
            }
        }


    fun fetchLocation():Boolean{
        val task = fusedLocationProviderClient.lastLocation
        if(ActivityCompat.checkSelfPermission(application,android.Manifest.permission.ACCESS_FINE_LOCATION)
            !=PackageManager.PERMISSION_GRANTED &&
            ActivityCompat.checkSelfPermission(application,android.Manifest.permission.ACCESS_COARSE_LOCATION)
            !=PackageManager.PERMISSION_GRANTED
        ){
            return true
        }
        task.addOnSuccessListener {
            if(it!=null){
                getWeather(it.latitude,it.longitude)
                getAddressName(it.latitude,it.longitude)
                Log.d("localityname", locality)
            }
        }
        return true

    }

    private fun fetchLocationDetails(){

    }
    private fun getAddressName(lat:Double,long:Double):String{

        var addressName = " "
        val geoCoder = Geocoder(application, Locale.getDefault())
        val address = geoCoder.getFromLocation(lat,long,1)
        if (address != null) {
            addressName = address[0].adminArea
        }
        locality = addressName

        Log.d("subadmin",addressName.toString())
        Log.d("Address", addressName)
        return addressName


    }

    fun getCoordinates(cord:String){
        val geocoder = Geocoder(application,Locale.getDefault())
        val address = geocoder.getFromLocationName(cord,2)
        val result = address?.get(0)
        if (result != null) {



            getWeather(result.latitude,result.longitude)
            getAddressName(result.latitude,result.longitude)
        }

    }






}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-11-10 12:53:14

,所以我使用的是类型转换器类,但是我感到困惑。

SQLite (其周围的数据库是面向对象的包装器)不是面向对象的(或感知的)数据库。它是一个数据库,它可以存储数据的基本类型,这些数据类型是

  • 整数(如Int或Long)、真实的
  • REAL(如浮点数或双)
  • 文本(例如字符串)
  • BLOB(如
  • )

因此,存储一种Coord,云或天气.你有三种选择:-

  1. 来嵌入类,在这种情况下,字段是从嵌入类复制的(如果嵌入的类包含不受支持的类型,则会很复杂)。answer
  2. to中没有涵盖的将类作为一个表,并在它与父类(WeatherDTO)之间建立关系。answer
  3. to中没有涵盖的将类转换为SQLite类型之一(其中的文本或BLOB很可能只是实用的)。

考虑到转换数据的选项3 (TyepConverters)很少(如果有的话),只使用存储数据,因为您将无法检索数据。

因此,应始终对转换器进行配对。

  • 一对中的一个将从类转换为可以存储的类型。
  • ,另一个将从存储的类型转换为.

。

因此,您将需要相当多的类型转换器,即每个字段需要2台:-

Clouds)

  • coord (类Coord)

  • main (class Main)

  • sys (类Sys)

  • 天气(类列表)

H 143风(类风)<代码>H 244<代码>F 245

房间查看的是字段的类,以找到相应的类型转换器。

转换对象(也称为类)的最简单方法之一是将对象转换为JSON表示。虽然这方面的一个复杂性是有许多JSON库,而且它们通常会有差异。

对于下面的例子,已经使用了JSON库。然而,这个库的使用似乎并不直接支持使用List,例如List。

这个依赖项(例如,implementation 'com.google.code.gson:gson:2.10' )

作为绕过一个新类,WeatherList使用了如下所示:-

代码语言:javascript
复制
data class WeatherList(
    val weatherList: List<Weather>
)

WeatherDTO类已经更改为使用它,如下所示:-

代码语言:javascript
复制
....
//val weather: List<Weather>,
val weather: WeatherList,
....

因此,TypeConverters类可以是:-

代码语言:javascript
复制
class TypeConverters {
    @TypeConverter
    fun fromCloudsToJSONString(clouds: Clouds): String = Gson().toJson(clouds)
    @TypeConverter
    fun toCloudsFromJSONString(jsonString: String): Clouds = Gson().fromJson(jsonString,Clouds::class.java)
    @TypeConverter
    fun fromCoordToJSONString(coord: Coord): String = Gson().toJson(coord)
    @TypeConverter
    fun toCoordFromJSONString(jsonString: String): Coord = Gson().fromJson(jsonString,Coord::class.java)
    @TypeConverter
    fun fromMaintoJSONString(main: Main): String = Gson().toJson(main)
    @TypeConverter
    fun toMainFromJSONString(jsonString: String): Main = Gson().fromJson(jsonString,Main::class.java)
    @TypeConverter
    fun fromSysToJSONString(sys: Sys): String = Gson().toJson(sys)
    @TypeConverter
    fun toSysFromJSONString(jsonString: String): Sys = Gson().fromJson(jsonString,Sys::class.java)
    @TypeConverter
    fun fromWeatherListFromJSONString(weatherList: WeatherList): String = Gson().toJson(weatherList)
    @TypeConverter
    fun toWeatherListFromJSOnString(jsonString: String): WeatherList = Gson().fromJson(jsonString,WeatherList::class.java)
    @TypeConverter
    fun fromWindToJSONString(wind: Wind): String = Gson().toJson(wind)
    @TypeConverter
    fun toWindFromJSONString(jsonString: String): Wind = Gson().fromJson(jsonString,Wind::class.java)
}

因此,所有不受直接支持的类型/类/对象都转换为/从类型/类/对象的JSON字符串表示形式转换。

请注意,您需要添加@TypeConverters(@TypeConverters( value = [<????>.TypeConverters::class])。在哪里必须区分您的项目-- TypeConverters类和Room类(TypeConverters可能不是该类的最佳名称,重新命名它,就可以克服区分的需要)

工作示例

以下内容将上述内容付诸实施。

由于问题中不包括底层类,因此使用了以下内容:

代码语言:javascript
复制
data class Coord(
    val longitude: Double,
    val latitude: Double
)
data class Clouds(
    val cover: Double,
    val type: String
)
data class Main(
    val main: Double
)
data class Sys(
    val sys: Double
)
data class WeatherList(
    val weatherList: List<Weather>
)
data class Weather(
    val weather: Double
)
data class Wind(
    val wind: Double
)

@Dao注释的接口也是由以下内容组成的:

代码语言:javascript
复制
@Dao
interface AllDao {
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    fun insert(weatherDTO: WeatherDTO)
    @Query("SELECT * FROM weatherdb")
    fun getAllFromWeatherDB(): List<WeatherDTO>
}

此外,@Database注释的抽象类是:-

代码语言:javascript
复制
@TypeConverters( value = [a.a.so74384736typeconverterconfusion.TypeConverters::class])
@Database(entities = [WeatherDTO::class], exportSchema = false, version = 1)
abstract class TheDatabase: RoomDatabase() {
    abstract fun getAllDao(): AllDao

    companion object {
        private var instance: TheDatabase? = null
        fun getInstance(context: Context): TheDatabase {
            if (instance==null) {
                instance = Room.databaseBuilder(context,TheDatabase::class.java,"the_database.db")
                    .allowMainThreadQueries()
                    .build()
            }
            return instance as TheDatabase
        }
    }
}

  • 注释用于区分TypeConverters类和TypeConverters类的TypeConverters类的包名

  • 包名不能在其他地方使用,所以如果复制了上面的内容,那么就必须对其进行更改。没有人期望完整的代码会被复制和使用。该代码仅用于演示TypeConverters.

最后一些实际操作的活动代码(存储和检索一些数据):-

代码语言:javascript
复制
class MainActivity : AppCompatActivity() {

    lateinit var db: TheDatabase
    lateinit var dao: AllDao
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        db = TheDatabase.getInstance(this)
        dao = db.getAllDao()

        dao.insert(
            WeatherDTO(
            "base001",
            Clouds(25.5,"cumulus"),10,
                Coord(10.567,30.345),
                11,
                12,
                Main(12345.67890),
                "thename",
                Sys(9.87654321),
                14,
                1000,
                WeatherList(listOf(Weather(5.1234),Weather(6.5432), Weather(7.6543))),
                Wind(23.12)
            )
        )
        for (wdto in dao.getAllFromWeatherDB()) {
            Log.d("DBINFO","base = ${wdto.base} longitude = ${wdto.coord.longitude} latitude = ${wdto.coord.latitude} etc ....")
        }
    }
}

结果

运行日志时,如预期的那样,包含:-

代码语言:javascript
复制
D/DBINFO: base = base001 longitude = 10.567 latitude = 30.345 etc ....

通过应用程序检查,数据库如下所示:

​

​

转换为JSON字符串的字段是highlighted.

  • Obviously,由于组合类的存在,数据很可能不完全像您预期的那样。
票数 0
EN

Stack Overflow用户

发布于 2022-11-10 07:40:12

这是我在科特林的转换器:

代码语言:javascript
复制
class Converters {

    @TypeConverter
    fun valueFromDomainToStorage(value: Value): String {
        return value.convertToJson()
    }

    @TypeConverter
    fun valueFromStorageToDomain(str: String): Value {
        // we can not create an empty instance of value as TypeDecoder.java should call non-empty constructor
        return Value(
            "just a stub",
            BigInteger.valueOf(0),
            BigInteger.valueOf(0),
            false,
            BigInteger.valueOf(0)
        )
            .fromJson(str)
    }
}

其中.convertToJson()和.fromJson(str)实现为Value类中的扩展:

代码语言:javascript
复制
fun Value.convertToJson(): String {
    val result = JSONObject()
    result.put(ValueConst.OFFER_FIELD, offer)
    result.put(ValueConst.AVAILABLE_SINCE, availableSince.toLong())
    result.put(ValueConst.AVAILABLE_END, availabilityEnd.toLong())
    result.put(ValueConst.IS_CONSUMED, isConsumed)
    result.put(ValueConst.LOCKED_UNTIL, lockedUntil)
    return result.toString()
}

fun Value.fromJson(json: String): Value {
    val subj = JSONObject(json)
    return Value(
        subj.optString(ValueConst.OFFER_FIELD),
        BigInteger.valueOf(subj.optLong(ValueConst.AVAILABLE_SINCE)),
        BigInteger.valueOf(subj.optLong(ValueConst.AVAILABLE_END)),
        subj.optBoolean(ValueConst.IS_CONSUMED),
        BigInteger.valueOf(subj.optLong(ValueConst.LOCKED_UNTIL))
    )
}

您应该为每个非本机类类型实现Converter类。不要忘记在数据库中注册转换器:

代码语言:javascript
复制
@Database(entities = [ChainTransaction::class], version = 1, exportSchema = false)
@TypeConverters(Converters::class)
abstract class AppDatabase: RoomDatabase() {

在编译代码并在以后引入新的更改时,还必须增加version参数才能生效:

代码语言:javascript
复制
@Database(entities = [ChainTransaction::class], version = 2, exportSchema = false)
@TypeConverters(Converters::class)
abstract class AppDatabase: RoomDatabase() {

这里是关于这个主题的正式文档,甚至是培训:https://developer.android.com/training/data-storage/room

票数 2
EN

Stack Overflow用户

发布于 2022-11-11 01:06:38

按照前面的答案@Embedded与类型转换器

从前面的答案可以看出,在使用TypeConverters方面存在一些问题。从数据库的角度来看,TypeConverters不可避免地会包含大量/不可缺少的数据,这与标准化(而不是不必要地存储重复数据)背道而驰。

例如,对于每一行,JSON表示将包含与字段名完全相同的占用存储空间的字段名,所有行都将具有存储分隔符的额外开销([s和]s、{s和}s、:s ,s)。此外,实际上,使用存储的数据可能会由于膨胀而变得复杂,也可能由于多个值存储在单个列中,因此可能是限制性的。

它将更有效地不存储膨胀,它可以消除复杂性和提高存储数据的可用性从数据库的角度(查询数据进行检索),而不是存储在一列多个值。

使用@Embedded注释可以很容易地消除浮肿。考虑以下几点( WeatherDTO类/实体的替代版本):

代码语言:javascript
复制
@Entity(tableName = "WeatherDbAlternative1")
data class WeatherDTOAlternative1(
    val base: String,
    @Embedded
    val clouds: Clouds,
    val cod: Int,
    @Embedded
    val coord: Coord,
    val dt: Int,
    @PrimaryKey(autoGenerate = true)
    val id: Int,
    @Embedded
    val main: Main,
    val name: String,
    @Embedded
    val sys: Sys,
    val timezone: Int,
    val visibility: Int,
    //val weather: List<Weather>,
    /* Unable to embed directly so not embedding */
    val weather: WeatherList,
    @Embedded
    val wind: Wind
)

除了天气字段之外,所做的就是添加@Embedded注释。注意到字段的类都有由Room直接支持的类型字段。

将该实体添加到@Database注释中,并在@Dao注释类中添加几个附加函数,如下所示:

代码语言:javascript
复制
@Query("SELECT * FROM weatherdbalternative1")
fun getAllFromWeatherDBAlternative1(): List<WeatherDTOAlternative1>
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(weatherDTOAlternative1: WeatherDTOAlternative1)

然后修订活动守则,包括:

代码语言:javascript
复制
    /*ALTERNATIVE 1 All but WeatherList embedded */
    dao.insert(
        WeatherDTOAlternative1(
            "base001A",
            Clouds(25.5, "cumulus"),
            10,
            Coord(10.567, 30.345),
            11,
            12,
            Main(12345.67890),
            "thenameA1",
            Sys(9.87654321),
            14,
            1000,
            WeatherList(listOf(Weather(5.1234), Weather(6.5432), Weather(7.6543))),
            Wind(23.12)
        )
    )
    for (wdto in dao.getAllFromWeatherDBAlternative1()) {
        Log.d(
            "DBINFO",
            "base = ${wdto.base} longitude = ${wdto.coord.longitude} latitude = ${wdto.coord.latitude} etc ...."
        )
    }

现在记录的结果包括:-

代码语言:javascript
复制
D/DBINFO: base = base001 longitude = 10.567 latitude = 30.345 etc ....
D/DBINFO: base = base001A longitude = 10.567 latitude = 30.345 etc ....

  • ,即有效存储和检索

的相同数据。

然而,数据现在以下列形式存储在数据库中(忽略天气字段):

​

​

advantageous).

  • additionally

  • ,即存储的数据更干净,但牺牲了额外的列(虽然这些列可以是的,但不明显,但是具有@Embedded注释的字段不需要)。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74384736

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档