web-dev-qa-db-ja.com

Androidルーム永続ライブラリ-リストオブジェクトフィールドを持つクラスを挿入する方法

Androidルーム永続ライブラリ モデルオブジェクト全体を別のリストを持つテーブルに挿入する方法。

私の意味をお見せしましょう:

@Entity(tableName = TABLE_NAME)
public class CountryModel {

    public static final String TABLE_NAME = "Countries";

    @PrimaryKey
    private int idCountry;

    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;
    }

    /** 
        here i am providing a list of coutry information how to insert 
        this into db along with CountryModel at same time 
    **/
    public List<CountryLang> getCountryLang() {
        return countryLang;
    }

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

私のDAOは次のようになります:

@Dao
public interface CountriesDao{

    @Query("SELECT * FROM " + CountryModel.TABLE_NAME +" WHERE isoCode =:iso_code LIMIT 1")
    LiveData<List<CountryModel>> getCountry(String iso_code);

    @Query("SELECT * FROM " + CountryModel.TABLE_NAME )
    LiveData<List<CountryModel>> getAllCountriesInfo();

    @Insert(onConflict = REPLACE)
    Long[] addCountries(List<CountryModel> countryModel);

    @Delete
    void deleteCountry(CountryModel... countryModel);

    @Update(onConflict = REPLACE)
    void updateEvent(CountryModel... countryModel);
}

database.CountriesDao().addCountries(countryModel);を呼び出すと、次の部屋dbコンパイルエラーが表示されます。Error:(58、31)エラー:このフィールドをデータベースに保存する方法がわかりません。タイプコンバーターを追加することを検討できます。

countryLangという別のテーブルが必要ですか?もしそうなら、挿入ステートメントでそれらを接続するための部屋を指示する方法は?

CountryLangオブジェクト自体は次のようになります。

public class CountryLang {


    private int idCountry;

    private int idLang;

    private String name;

    public int getIdCountry() {
        return idCountry;
    }

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

    public int getIdLang() {
        return idLang;
    }

    public void setIdLang(int idLang) {
        this.idLang = idLang;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

応答は次のようになります。

"country_lang": [
      {
        "id_country": 2,
        "id_lang": 1,
        "name": "Austria"
      }
    ]

すべての国のため、ここでは1つ以上のアイテムになりません。 country_langリスト内の1つのアイテムのみを指定するのは快適です。したがって、country_langのテーブルを作成してから、CountryModelにリンクする方法をいくつか作成できます。しかし、どのように?外部キーを使用できますか?フラットファイルを使用する必要がないことを望んでいました。だからあなたのことをjsonとして保存する必要がありますか?一時的なスペースを使用しないことをお勧めしますか?代わりに何を使用しますか?

25
j2emanue

Omkarが言ったように、できません。ここでは、ドキュメントに従って常に@Ignoreアノテーションを使用する理由を説明します。 https://developer.Android.com/training/data-storage/room/referencing-data.html#understand-オブジェクト参照なし

テーブルのCountryオブジェクトを処理して、その能力のデータのみを取得します。 Languagesオブジェクトは別のテーブルに移動しますが、同じDaoを保持できます。

  • 国と言語のオブジェクトは独立しており、言語エンティティ(countryId、languageId)のフィールドでprimaryKeyを定義するだけです。アクティブなスレッドがワーカースレッドである場合、リポジトリクラスにそれらを連続して保存できます。Daoへの挿入の2つの要求。
  • 国オブジェクトを読み込むには、countryIdがあります。
  • 関連するLanguagesオブジェクトを読み込むには、すでにcountryIdがありますが、言語を読み込む前にその国が読み込まれるのを待つ必要があります。そのため、言語を親オブジェクトに設定して、親オブジェクトのみを返すことができます。
  • 国をロードするときに、おそらくリポジトリクラスでこれを連続して実行できるため、サーバー側で行うように、国と言語を同時にロードします! (ORMライブラリなし)。
11
Davideas

TypeConverterおよびGSONを使用して、リストオブジェクトフィールドを持つクラスを簡単に挿入できます。

public class DataConverter {

    @TypeConverter
    public String fromCountryLangList(List<CountryLang> countryLang) {
        if (countryLang == null) {
            return (null);
        }
        Gson gson = new Gson();
        Type type = new TypeToken<List<CountryLang>>() {}.getType();
        String json = gson.toJson(countryLang, type);
        return json;
    }

    @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;
    }
 }

リストオブジェクトフィールドの前に@TypeConverters注釈を追加し、

@Entity(tableName = TABLE_NAME)
public class CountryModel {

//....

@TypeConverters(DataConverter.class)
    public List<CountryLang> getCountryLang() {
        return countryLang;
    }
//....
} 

TypeConverters in Roomの詳細については、ブログ here および official docs をご覧ください。

57

コピーペーストを楽しむ怠け者のGoogle社員向けのKotlinにあるAman Guptaのコンバーターは次のとおりです。

class DataConverter {

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

    @TypeConverter
    fun toCountryLangList(value: String): List<CountryLang> {
        val gson = Gson()
        val type = object : TypeToken<List<CountryLang>>() {}.type
        return gson.fromJson(value, type)
    }
}
7
Daniel Wilson

できません。

これを達成する唯一の方法は、 @ ForeignKey 制約を使用することです。親POJO内にオブジェクトのリストを保持したい場合は、 @ Ignore を使用するか、 @ TypeConverter を指定する必要があります

詳細については、このブログの投稿に従ってください:

https://www.bignerdranch.com/blog/room-data-storage-for-everyone/

およびサンプルコード:-

https://github.com/googlesamples/Android-architecture-components

6
Omkar Amberkar

カスタムオブジェクトフィールドに@Embeddedを追加します(次の例を参照)

//this class refers to pojo which need to be stored
@Entity(tableName = "event_listing")
public class EventListingEntity implements Parcelable {

    @Embedded  // <<<< This is very Important in case of custom obj 
    @TypeConverters(Converters.class)
    @SerializedName("mapped")
    public ArrayList<MappedItem> mapped;

    //provide getter and setters
    //there should not the duplicate field names
}

//add converter so that we can store the custom object in ROOM database
public class Converters {
    //room will automatically convert custom obj into string and store in DB
    @TypeConverter
    public static String 
    convertMapArr(ArrayList<EventListingEntity.MappedItem> list) {
    Gson gson = new Gson();
    String json = gson.toJson(list);
    return json;
    }

  //At the time of fetching records room will automatically convert string to 
  // respective obj
  @TypeConverter
  public static ArrayList<EventsListingResponse.MappedItem> 
  toMappedItem(String value) {
    Type listType = new 
     TypeToken<ArrayList<EventsListingResponse.MappedItem>>() {
    }.getType();
    return new Gson().fromJson(value, listType);
  }

 }

//Final db class
@Database(entities = {EventsListingResponse.class}, version = 2)
@TypeConverters({Converters.class})
public abstract class AppDatabase extends RoomDatabase {
    ....
}
0
shashank J