Статьи

Работа с типом данных массива в таблице

В этой статье я хотел бы продолжить мою предыдущую статью о типах данных коллекции Oracle и сосредоточиться на работе с атрибутами oracle.jbo.domain.Array в компоненте af: table .

Итак, в моей базе данных у меня есть следующий тип SQL:

1
create or replace type varchar2_array_type as table of varchar2(200)  

И у меня есть следующая таблица:

1
2
3
4
create table testarray (
SomeField Number,
ArrValue VARCHAR2_ARRAY_TYPE)
nested table ArrValue store as arrvalue_tab return as value;

В модели ADF BC есть сущность, основанная на таблице testarray :

Снимок экрана 2014-04-25 в 17.06.18

Тип данных атрибута Arrvalueoracle.jbo.domain.Array.

В контейнере привязки есть соответствующий атрибут привязки:

1
2
3
4
5
    <attributeValues IterBinding="VTestarrayIterator" id="Arrvalue">
      <AttrNames>
        <Item Value="Arrvalue"/>
      </AttrNames>
    </attributeValues>

Самый простой способ отобразить значение этого атрибута может быть таким:

1
2
3
4
5
6
<af:table value="#{bindings.Arrvalue.inputValue.array}" var="row"
          id="t1">
   <af:column sortable="false" headerText="Array Values" id="c1">
      <af:inputText value="#{row}" id="ot3"/>            
   </af:column>
</af:table>

И результат выглядит довольно красиво:

Снимок экрана 2014-04-25 в 5.35.38 вечера

Единственная проблема с этим подходом состоит в том, что таблица не обновляется. Читается только один.

Выражение EL «# {bindings.Arrvalue.inputValue.array}» будет вызывать метод oracle.jbo.domain.Array.getArray (), который возвращает неизменный массив Object [], и все модификации этого массива будут потеряны.

Если нам необходимо обновить данные в таблице, мы должны сделать следующее:

  1. Сделайте копию привязок.Arrvalue.inputValue.array
  2. Установить эту копию как значение таблицы
  3. На этапе обновления значений модели оберните копию обратно в oracle.jbo.domain.Array и поместите ее в Arrvalue.inputValue.

Итак, мы собираемся сделать копию и сохранить ее в управляемом компоненте области запроса:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
private Object[] array = null;
 
private Object[] createArray() {
  JUCtrlValueBinding dcb = getArrayCtrlBinding();
  if (dcb!=null){
      Array arr = (Array) dcb.getInputValue();
      if (arr!=null) {
          array = arr.getArray();
      }         
  }
  return array;
}
 
 
public void setArray(Object[] array) {
    this.array = array;
}
 
public Object[] getArray() {
    return (array == null ? createArray() : array);
}
 
     
private JUCtrlValueBinding getArrayCtrlBinding() {
  BindingContext bc = BindingContext.getCurrent();
  DCBindingContainer binding = (DCBindingContainer) bc.getCurrentBindingsEntry();
  return (JUCtrlValueBinding ) binding.findCtrlBinding("Arrvalue");
}

Когда дело доходит до использования этой копии в качестве значения таблицы, мы можем сделать следующее:

1
2
3
4
5
6
7
  <af:table value="#{TheBean.array}" var="row"
            id="t1"
            varStatus="status">
    <af:column sortable="false" headerText="Array Values" id="c1">
       <af:inputText value="#{TheBean.array[status.index]}" id="ot3"/>            
    </af:column>
  </af:table>

Обратите внимание, что мы не использовали просто # {row} в качестве значения inputText. Это не сработает, поскольку # {row} просто возвращает неизменяемую строку. Вместо этого мы использовали атрибут таблицы varStatus . Выражение EL # {TheBean.array [status.index]} позволяет платформе вызывать соответствующий метод установки на этапе обновления значений модели, поэтому все изменения, сделанные в таблице, будут сохранены в TheBean.array .

Последний шаг — вернуть TheBean.array в значение атрибута на этапе обновления значений модели. Мы можем использовать поддельный невидимый inputText для этой цели:

1
2
3
4
<af:inputText value="#{TheBean.dummy}"
              visible="false"
              converter="EmptyConverter"
              id="it2"/>

Этот входной текст должен быть размещен под таблицей на странице. Прелесть этого подхода в том, что фреймворк будет пытаться обновлять значение inputText при каждом запросе. Таким образом, метод установки TheBean.setDummy (String dummy) будет вызываться при каждом запросе на этапе обновления значений модели модели сразу после сохранения значений таблицы в TheBean.array . И в этот момент мы собираемся обернуть массив в oracle.jbo.domain.Array и вернуть его обратно в Arrvalue.inputValue :

1
2
3
4
public void setDummy(String dummy) {
  getArrayCtrlBinding().setInputValue(new Array(array));  
  array = null;
}

Секрет этого фиктивного inputText скрыт в EmptyConverter:

01
02
03
04
05
06
07
08
09
10
11
public class EmptyConverter implements Converter {
 public Object getAsObject(FacesContext facesContext,
                           UIComponent uIComponent, String string) {
     return null;
 }
 
 public String getAsString(FacesContext facesContext,
                           UIComponent uIComponent, Object object) {
     return null;
 }
}

Он эмулирует, что нулевое значение было отправлено для этого компонента вместе с запросом. С другой стороны, фиктивный метод получения всегда возвращает ненулевое значение:

1
2
3
 public String getDummy() {
    return DUMMY;
 }

Таким образом, у фреймворка нет другого выбора, кроме как вызвать метод setDummy на этапе обновления значений модели.

Пример приложения для этого поста требует JDeveloper 11.1.1.7.

Это оно!

Ссылка: Работа с типом данных массива в таблице от нашего партнера по JCG Евгения Федоренко в блоге ADF Practice .