67

由于错误,我无法在房间中创建 typeConverter。我似乎遵循文档中的所有内容。我想将列表转换为 json 字符串。让我们看看我的实体:

      @Entity(tableName = TABLE_NAME)
public class CountryModel {

    public static final String TABLE_NAME = "Countries";

    @PrimaryKey
    private int idCountry;
/* I WANT TO CONVERT THIS LIST TO A JSON STRING */
    private List<CountryLang> countryLang = null;

    public int getIdCountry() {
        return idCountry;
    }

    public void setIdCountry(int idCountry) {
        this.idCountry = idCountry;
    }

    public String getIsoCode() {
        return isoCode;
    }

    public void setIsoCode(String isoCode) {
        this.isoCode = isoCode;
    }

    public List<CountryLang> getCountryLang() {
        return countryLang;
    }

    public void setCountryLang(List<CountryLang> countryLang) {
        this.countryLang = countryLang;
    }

}

country_lang是我想转换为字符串 json 的内容。所以我创建了以下转换器:Converters.java:

public class Converters {

@TypeConverter
public static String countryLangToJson(List<CountryLang> list) {

    if(list == null)
        return null;

        CountryLang lang = list.get(0);

    return list.isEmpty() ? null : new Gson().toJson(lang);
}}

那么问题出在我放置@TypeConverters({Converters.class}) 的任何地方,我一直收到错误消息。但正式这是我放置注释以注册 typeConverter 的地方:

@Database(entities = {CountryModel.class}, version = 1 ,exportSchema = false)
@TypeConverters({Converters.class})
public abstract class MYDatabase extends RoomDatabase {
    public abstract CountriesDao countriesDao();
}

我得到的错误是:

Error:(58, 31) error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
4

14 回答 14

44

这是自从 Room 发布以来我看到的一个常见问题。Room 不支持直接存储列表的能力,也不支持与列表相互转换的能力。它支持转换和存储 POJO。

在这种情况下,解决方案很简单。而不是存储List<CountryLang>你想要存储的CountryLangs(注意's')

我在这里做了一个解决方案的简单示例:

public class CountryLangs {
    private List<String> countryLangs;

    public CountryLangs(List<String> countryLangs) {
        this.countryLangs = countryLangs;
    }

    public List<String> getCountryLangs() {
        return countryLangs;
    }

    public void setCountryLangs(List<String> countryLangs) {
        this.countryLangs = countryLangs;
    }
}

此 POJO 是您先前对象的反转。它是一个存储语言列表的对象。而不是存储您的语言的对象列表。

public class LanguageConverter {
    @TypeConverter
    public CountryLangs storedStringToLanguages(String value) {
        List<String> langs = Arrays.asList(value.split("\\s*,\\s*"));
        return new CountryLangs(langs);
    }

    @TypeConverter
    public String languagesToStoredString(CountryLangs cl) {
        String value = "";

        for (String lang :cl.getCountryLangs())
            value += lang + ",";

        return value;
    }
}

此转换器获取字符串列表并将它们转换为逗号分隔的字符串以存储在单个列中。当它从 SQLite 数据库中获取字符串以转换回来时,它会用逗号分割列表,并填充 CountryLangs。

确保在进行这些更改后更新您的 RoomDatabase 版本。您的其余配置正确。与您余下的 Room 持久性工作一起愉快地狩猎。

于 2017-06-18T13:59:09.563 回答
32

尝试添加日期字段时出现相同的错误:“无法弄清楚如何将此字段保存到数据库中”。必须为其添加一个转换器类并将@TypeConverters 注释添加到字段。

例子:

WordEntity.java

import androidx.room.TypeConverters;

@Entity
public class WordEntity {

    @PrimaryKey(autoGenerate = true)
    public int id;

    private String name;

    @TypeConverters(DateConverter.class)
    private Date createDate;

    ...
}

日期转换器.java:

import androidx.room.TypeConverter;    
import java.util.Date;

public class DateConverter {

    @TypeConverter
    public static Date toDate(Long timestamp) {
        return timestamp == null ? null : new Date(timestamp);
    }

    @TypeConverter
    public static Long toTimestamp(Date date) {
        return date == null ? null : date.getTime();
    }
}
于 2017-12-23T17:41:05.200 回答
11

我使用了此处描述的类型转换器(Medium.com 上的文章)并且它有效:

@TypeConverter
    public static List<MyObject> storedStringToMyObjects(String data) {
        Gson gson = new Gson();
        if (data == null) {
            return Collections.emptyList();
        }
        Type listType = new TypeToken<List<MyObject>>() {}.getType();
        return gson.fromJson(data, listType);
    }

    @TypeConverter
    public static String myObjectsToStoredString(List<MyObject> myObjects) {
        Gson gson = new Gson();
        return gson.toJson(myObjects);
    }
于 2018-12-23T10:45:42.320 回答
5

以防万一你需要更清楚。

首先创建一个转换器通用类,如下所示。

class Converters {

@TypeConverter
fun fromGroupTaskMemberList(value: List<Comment>): String {
    val gson = Gson()
    val type = object : TypeToken<List<Comment>>() {}.type
    return gson.toJson(value, type)
}

@TypeConverter
fun toGroupTaskMemberList(value: String): List<Comment> {
    val gson = Gson()
    val type = object : TypeToken<List<Comment>>() {}.type
    return gson.fromJson(value, type)
}

}

然后在数据库类中添加这个转换器,就像,

@TypeConverters(Converters::class)

抽象类 AppDatabase : RoomDatabase() {

于 2020-05-06T11:37:29.317 回答
4

@TypeConverter不识别List类,因此您应该ArrayList改用,因此您不需要为要保留的列表添加额外的包装器。

于 2018-01-12T14:21:27.977 回答
4

只需使用 @Embedded 注释该对象即可解决我的问题。像这样

@Embedded
private List<CrewListBean> crewList;
于 2019-10-09T07:46:04.737 回答
4

我可能会迟到回答但是。我有一些简单的解决方案我正在共享处理一些基本要求的 TypeConverter的调用

class RoomConverters {
//for date and time convertions
@TypeConverter
fun calendarToDateStamp(calendar: Calendar): Long = calendar.timeInMillis

@TypeConverter
fun dateStampToCalendar(value: Long): Calendar =
    Calendar.getInstance().apply { timeInMillis = value }

//list of cutome object in your database
@TypeConverter
fun saveAddressList(listOfString: List<AddressDTO?>?): String? {
    return Gson().toJson(listOfString)
}

@TypeConverter
fun getAddressList(listOfString: String?): List<AddressDTO?>? {
    return Gson().fromJson(
        listOfString,
        object : TypeToken<List<String?>?>() {}.type
    )
}

/*  for converting List<Double?>?  you can do same with other data type*/
@TypeConverter
fun saveDoubleList(listOfString: List<Double>): String? {
    return Gson().toJson(listOfString)
}

@TypeConverter
fun getDoubleList(listOfString: List<Double>): List<Double> {
    return Gson().fromJson(
        listOfString.toString(),
        object : TypeToken<List<Double?>?>() {}.type
    )
}

// for converting the json object or String into Pojo or DTO class
@TypeConverter
fun toCurrentLocationDTO(value: String?): CurrentLocationDTO {
    return  Gson().fromJson(
        value,
        object : TypeToken<CurrentLocationDTO?>() {}.type
    )
}

@TypeConverter
fun fromCurrentLocationDTO(categories: CurrentLocationDTO?): String {
    return Gson().toJson(categories)

}

}

您必须编写自己的类并在此处解析,然后将其添加到您的 AppDatabase 类

@Database(
        entities = [UserDTO::class],
        version = 1, exportSchema = false
         ) 
@TypeConverters(RoomConverters::class)
@Singleton
abstract class AppDatabase : RoomDatabase() {
于 2020-05-09T08:42:35.897 回答
3

Kotlin 示例(不好但简单,TODO: json):

import android.arch.persistence.room.*

@Entity(tableName = "doctor")
data class DoctorEntity(

    @PrimaryKey
    @ColumnInfo(name = "id") val id: Long,

    @ColumnInfo(name = "contactName") val contactName: String?,

    @TypeConverters(CategoryConverter::class)
    @ColumnInfo(name = "categories") val categories: Categories?,

    @TypeConverters(CategoryConverter::class)
    @ColumnInfo(name = "languages") val languages: Categories?
) 

data class Categories(
    val categories: ArrayList<Long> = ArrayList()
)

class CategoryConverter {

    @TypeConverter
    fun toCategories(value: String?): Categories {
        if (value == null || value.isEmpty()) {
            return Categories()
        }

        val list: List<String> = value.split(",")
        val longList = ArrayList<Long>()
        for (item in list) {
            if (!item.isEmpty()) {
                longList.add(item.toLong())
            }
        }
        return Categories(longList)
    }

    @TypeConverter
    fun toString(categories: Categories?): String {

        var string = ""

        if (categories == null) {
            return string
        }

        categories.categories.forEach {
            string += "$it,"
        }
        return string
    }
}
于 2018-07-09T07:52:44.750 回答
1

您还必须创建它TypeConverter,它将您转换ListString,

@TypeConverter
public List<CountryLang> toCountryLangList(String countryLangString) {
    if (countryLangString == null) {
        return (null);
    }
    Gson gson = new Gson();
    Type type = new TypeToken<List<CountryLang>>() {}.getType();
    List<CountryLang> countryLangList = gson.fromJson(countryLangString, type);
    return countryLangList;
}

有关更多信息,您还可以查看我的另一个答案

于 2018-03-09T11:43:15.677 回答
1

如果您想使自定义类兼容(不同于受支持的类),您必须提供一个双向 @TypeConverter 转换器,它将自定义类转换为 Room 已知的类,反之亦然。

例如,如果我们想保留 LatLng 的实例:

前提: implementation("com.squareup.moshi:moshi-kotlin:1.9.2")

转换器.kt

@TypeConverter
fun stringToLatLng(input: String?): LatLng? =
        input?.let { Moshi.Builder().build().adapter(LatLng::class.java).fromJson(it) }

@TypeConverter
fun latLngToString(input: LatLng): String? =
        Moshi.Builder().build().adapter(LatLng::class.java).toJson(input)

Room 已经知道如何存储字符串。

使用这些转换器,您可以在其他查​​询中使用自定义类型,就像使用原始类型一样

位置.kt

@Entity
data class Location(private val location: LatLng?)

总帐

来源

于 2020-05-04T18:13:33.850 回答
1

这里给出的解决方案是不完整的,一旦你完成了接受的答案中给出的过程,你还需要在你的实体类中添加另一个注释

@TypeConverters(Converter.class)
private List<String> brandId;

这应该放在导致 Room DB 错误的元素上

快乐编码

于 2020-07-29T20:45:19.723 回答
1

对于仅使用此类型转换器的所有对象,您可以避免对象到字符串(json)类型转换器

@TypeConverter
    fun objectToJson(value: Any?) = Gson().toJson(value)
 

我使用它并且必须只定义字符串(json)到对象的转换器,例如。

@TypeConverter
    fun stringToPersonObject(string: String?): Person? {
        return Gson().fromJson(string, Person::class.java)
    }
于 2021-04-27T16:36:12.467 回答
0

可以来回@TypeConverter组织@TypeConverters

public class DateConverter {
    @TypeConverter
    public long from(Date value) {
        return value.getTime();
    }
    @TypeConverter
    public Date to(long value) {
        return new Date(value);
    }
}

然后将它们应用于以下字段:

@TypeConverters(DateConverter.class)
于 2021-11-03T05:23:17.523 回答
-1

有同样的问题。将 更改ListArrayList。该列表是一个接口,房间无法存储它。

于 2019-05-28T06:48:14.340 回答