質問

誰もが1対多マッピングを実装する方法について良いアドバイスを持っています SQLite 使用 ContentProvider?あなたが見たら Uri ContentProvider#insert(Uri, ContentValues) あなたはそれが持っていることを見ることができます ContentValues 挿入するデータを含むPARAM。問題は、現在の実装においてです ContentValues サポートしていません put(String, Object) 方法とクラスが最終的なので、拡張できません。なぜそれが問題なのですか?ここに私のデザインがあります:

1対多数の関係にある2つのテーブルがあります。これらをコードで表すには、2つのモデルオブジェクトがあります。 1番目はメインレコードを表し、2番目のオブジェクトインスタンスのリストであるフィールドがあります。これで、モデルオブジェクト#1にヘルパーメソッドがあります。 ContentValues 現在のオブジェクトから生成されました。プリミティブフィールドを入力するのは些細なことです ContentValues#put 過負荷の方法ですが、私はリストのために運が悪いです。だから現在、私の2番目のテーブル行が単一の文字列値であるため、私はコンマの区切り文字列を生成します。 ContentProvider#insert. 。それは不快に感じるので、誰かがそれがよりクリーンな方法でどのようにできるかをほのめかすことができるかもしれません。

これがいくつかのコードです。モデルクラスから最初:

public ContentValues toContentValues() {
    ContentValues values = new ContentValues();
    values.put(ITEM_ID, itemId);
    values.put(NAME, name);
    values.put(TYPES, concat(types));
    return values;
}

private String concat(String[] values) { /* trivial */}

そして、これがスリムなダウンバージョンです ContentProvider#insert 方法

public Uri insert(Uri uri, ContentValues values) {
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    db.beginTransaction();
    try {
        // populate types
        String[] types = ((String)values.get(Offer.TYPES)).split("|");
        // we no longer need it
        values.remove(Offer.TYPES);
        // first insert row into OFFERS
        final long rowId = db.insert("offers", Offer.NAME, values);
        if (rowId > 0 && types != null) {
            // now insert all types for the row
            for (String t : types) {
                ContentValues type = new ContentValues(8);
                type.put(Offer.OFFER_ID, rowId);
                type.put(Offer.TYPE, t);
                // insert values into second table
                db.insert("types", Offer.TYPE, type);
            }
        }
        db.setTransactionSuccessful();
        return ContentUris.withAppendedId(Offer.CONTENT_URI, rowId);
    } catch (Exception e) {
        Log.e(TAG, "Failed to insert record", e);
    } finally {
        db.endTransaction();
    }

}
役に立ちましたか?

解決

私はあなたが一つの関係の間違った終わりを見ていると思います。

を見てください ContactsContract たとえば、コンテンツプロバイダー。連絡先は、多くのメールアドレス、多くの電話番号などを持つことができます。 "たくさんの" 側。新しい電話番号を追加するには、新しい電話番号を挿入して、電話番号が関係する連絡先のIDを提供します。

コンテンツプロバイダーのないプレーンSQLiteデータベースがある場合、同じことをします。リレーショナルデータベースの1対多くの関係は、「多くの」側のテーブルの挿入/更新/削除を介して達成され、それぞれが「1つの」側に外部キーを持っています。

今、OOの観点から、これは理想的ではありません。 「1つの」側から子供のコレクションを操作できるORMスタイルのラッパーオブジェクト(Hibernateを考えてください)を作成できます。その後、十分に知性のあるコレクションクラスが向きを変えて、「多くの」テーブルを同期して一致させることができます。ただし、これらは必ずしも適切に実装する些細なものではありません。

他のヒント

使用できます ContentProviderOperations このため。

それらは基本的に、親の行に生成された識別子に戻ることができる能力を備えたバルク操作です。

どのように ContentProviderOperations 1対多様なデザインに使用できます。この答えでは非常によく説明されています。 withvaluebackreferenceのセマンティクスは何ですか?

だから私は自分の質問に答えるつもりです。私は2つのテーブルと2つのモデルオブジェクトを持っていることで正しい軌道に乗っていました。不足していて、私を混乱させたのは、複雑なデータを直接挿入したいということでした ContentProvider#insert 1回の呼び出しで。これは間違っています。 ContentProvider これらの2つのテーブルを作成および維持する必要がありますが、どのテーブルを使用するかを決定する決定は、 ContentProvider#insert. 。 ContentResolverを使用し、モデルオブジェクトに「AddFoo」などのメソッドを追加するのは非常に便利です。このような方法はContentResolverパラメーターを取り、最後に複雑なレコードを挿入するシーケンスがあります。

  1. 親の記録を挿入します ContentProvider#insert 記録IDを取得します
  2. 各子供ごとに親ID(foregn key)を提供し、使用します ContentProvider#insert 異なるURIを使用して、子の記録を挿入します

したがって、残っている唯一の質問は、上記のコードをトランザクションに封入する方法です。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top