Какова семантика withValueBackReference?

Я не могу понять точную семантику сValueBackReference.

Я прочитал пример кода (например, код, который добавляет новый контакт) с использованием этого метода, предоставив значение backReference равное 0. Что это значит?

В документации говорится:

Значение столбца из обратных ссылок имеет приоритет над значением, указанным в withValues(ContentValues)


person curioustechizen    schedule 11.01.2011    source источник
comment
Я нашел это обсуждение на SO - в нем говорится об использовании метода withValueBackReference в случае, когда целью является сохранение основной и подробной записей за одну операцию. Тем не менее, я до сих пор не понимаю, как здесь значение обратной ссылки равно 0! stackoverflow.com/questions/3224857/   -  person curioustechizen    schedule 12.01.2011


Ответы (1)


Этот вопрос относится к пакетной операции с поставщиком контента. Пример изменен из этого связанного вопроса.

При создании пакета операций сначала создайте список операций для выполнения, используя:

ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();

затем примените их к поставщику контента с помощью метода applyBatch.

ContentProviderResult[] results = this.getContentResolver().applyBatch(FooBar.AUTHORITY, operations);

Это основная концепция, поэтому давайте применим ее. Предположим, у нас есть контент-провайдер, который обрабатывает uris для записей Foo и некоторых дочерних записей с именем Bar.

контент://com.stackoverflow.foobar/foo

содержимое://com.stackoverflow.foobar/foo/#/бар

Сейчас мы просто вставим 2 новые записи Foo, называемые Foo A и Foo B, вот пример.

ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();

//add a new ContentProviderOperation - inserting a FOO record with a name and a decscription
operations.add(ContentProviderOperation.newInsert(intent.getData())
    .withValue(FOO.NAME, "Foo A")
    .withValue(FOO.DESCRIPTION, "A foo of impeccable nature")
    .build());

//let's add another
operations.add(ContentProviderOperation.newInsert(intent.getData())
    .withValue(FOO.NAME, "Foo B")
    .withValue(FOO.DESCRIPTION, "A foo of despicable nature")
    .build());

ContentProviderResult[] results = this.getContentResolver().applyBatch(FooBar.AUTHORITY, operations);

Здесь ничего особенного, мы добавляем 2 элемента ContentProviderOperation в наш список, а затем применяем этот список к нашему контент-провайдеру. Массив результатов заполнен идентификаторами новых записей, которые мы только что вставили.

Итак, скажем, мы хотели сделать что-то подобное, но мы также хотим добавить несколько дочерних записей в наш поставщик содержимого в одной пакетной операции. Мы хотим прикрепить дочерние записи к только что созданным записям Foo. Проблема в том, что мы не знаем идентификатор родительских записей Foo, потому что пакет не был запущен. Здесь нам помогает withValueBackReference. Давайте посмотрим пример:

ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();

//add a new ContentProviderOperation - inserting a Foo record with a name and a decscription
operations.add(ContentProviderOperation.newInsert(intent.getData())
    .withValue(FOO.NAME, "Foo A")
    .withValue(FOO.DESCRIPTION, "Foo of impeccable nature")
    .build());

//let's add another
operations.add(ContentProviderOperation.newInsert(intent.getData())
    .withValue(FOO.NAME, "Foo B")
    .withValue(FOO.DESCRIPTION, "Foo of despicable nature")
    .build());

//now add a Bar record called [Barbarella] and relate it to [Foo A]
operations.add(ContentProviderOperation.newInsert(intent.getData()
    .buildUpon()
    .appendPath("#") /* We don't know this yet */
    .appendPath("bar")
    .build())
.withValueBackReference (BAR.FOO_ID, 0) /* Index is 0 because Foo A is the first operation in the array*/
.withValue(BAR.NAME, "Barbarella")
.withValue(BAR.GENDER, "female")
.build());

//add a Bar record called [Barbarian] and relate it to [Foo B]
operations.add(ContentProviderOperation.newInsert(intent.getData()
    .buildUpon()
    .appendPath("#") /* We don't know this yet */
    .appendPath("bar")
    .build())
.withValueBackReference (BAR.FOO_ID, 1) /* Index of parent Foo B is 1*/
.withValue(BAR.NAME, "Barbarian")
.withValue(BAR.GENDER, "male")
.build());

ContentProviderResult[] results = this.getContentResolver().applyBatch(FooBar.AUTHORITY, operations);

Таким образом, метод withValueBackReference() позволяет нам вставлять связанные записи до того, как мы узнаем идентификатор родителя, с которым мы хотим их связать. Индекс обратной ссылки — это просто индекс операции, которая вернет идентификатор, который мы хотим найти. Возможно, проще думать об этом с точки зрения того, какой результат вы ожидаете содержать идентификатор. например, results[1] будет содержать идентификатор для Foo B, поэтому индекс, который мы используем для обратной ссылки на Foo B, равен 1.

person Moog    schedule 19.07.2011
comment
Это было безупречное объяснение. Благодаря тонну! Как бы я хотел, чтобы я мог голосовать больше, чем один раз. - person curioustechizen; 19.07.2011
comment
Это золото, одно из немногих приличных объяснений обратных ссылок, которые я видел. У меня это реализовано в моем приложении - спасибо - person David Snabel-Caunt; 26.10.2011
comment
Лучший ответ, большое спасибо, будет хорошо иметь звездный флаг, который вы можете поставить только в 5 ответах :) У вас определенно есть такой! - person Goofyahead; 21.05.2012
comment
Большое спасибо. Устранил некоторую путаницу :) - person DanielGrech; 19.07.2012
comment
Это отличный ответ. Я думаю, было бы еще понятнее добавить предложение или объяснить, на что на самом деле указывает в вашем примере намерение.getData(). Если я правильно читаю код, это URI контента (тип операции), и в вашем примере его можно поменять местами с BAR.FOO_ID. Таким образом, система позволяет указать N-й результат операции типа BAR.FOO_ID. Я прав в этом? - person GolfARama; 06.01.2013
comment
В этом примере intent.getData() эквивалентно Uri.parse("content://com.stackoverflow.foobar/foo"). - person Moog; 17.01.2013
comment
Вы уверены, что замена знака # в content://com.stackoverflow.foobar/foo/#/bar на идентификатор основной записи действительно работает? Я попробовал, и кажется, что это не так. Если я загляну в источник ContentProviderOperation кажется, что обратные ссылки применяются только к ContentValues, не URI. - person aha; 07.03.2013
comment
Мерлин, у меня тот же вопрос, что и у @aha. У меня не было возможности очень глубоко изучить код, на который он указал, поэтому я не могу сказать, есть ли эта конкретная реализация с этой проблемой или нет. В любом случае, меня больше беспокоит контракт. При чем тут договор? - person batbrat; 22.03.2014
comment
Отличное объяснение и познакомило меня с функцией, которая избавила меня от многих часов боли. С благодарностью. - person Mark OB; 01.11.2014
comment
Спасибо, чувак, ты спас мой день ...., даже в документации по Android отсутствуют эти детали API. - person Sanath; 23.02.2017
comment
Это будет работать только в случае отношения master-detail? Я пытался сделать то же самое, но без структуры master-detail, проблема в том, что withValueBackReference возвращает имя первой таблицы. - person cylon; 25.07.2017
comment
@cylon — это вариант использования по умолчанию, но вы можете найти для него более творческие применения. - person Moog; 03.08.2017
comment
Как насчет ситуации с обновлением, когда у вас уже должен быть RAW_CONTACT_ID, к чему тогда относится второй параметр? - person NVA; 11.03.2018
comment
Если вы уже знаете идентификатор родителя, вы просто используете withValue(...) вместо withValueBackReference(..., index), чтобы не было второго параметра. - person Moog; 25.06.2019