2015-07-10 5 views
2

Дано below пример <p:dataTable> с использованием ленивой модели данных PrimeFaces. Поле версии строки, помеченное как @javax.persistence.Version в ассоциированном объекте JPA, временно отображается в одном из столбцов в режиме только для чтения.p: dataTable и оптимистичная блокировка в JPA

Нет необходимости упомянуть, что каждое действие является Ajaxical.

enter image description here

Редактирование этого <p:dataTable> использованием <p:rowEditor/> как follows (первая строка в таблице. версия строка 1).

enter image description here

Когда строка редактируется обновляется, нажав на галочку в Edit колонке, как описано выше, версия строки увеличивается в базе данных до 2 об успешном обновлении, но версия строки принадлежат таблицы данных по-прежнему 1 (см. рисунок ниже). После завершения обновления статус таблицы данных можно просмотреть как follows.

enter image description here

Что происходит сейчас, если та же строка снова пытался (без перезагрузки страницы, отправив запрос на синхронную GET), то она не будет соответствовать версии строки в базе данных, которая в настоящее время 2, так как таблица данных по-прежнему поставляет прежнее предыдущее значение версии, которое равно 1. Это приведет к тому, что javax.persistence.OptimisticLockException будет выбрасываться, как если бы обнаружены параллельные обновления, что, очевидно, неверно.

Что-то, возможно, потребуется изменить коренным образом в обычном Ajaxical объекта обновления, предоставляемом <p:dataTable> (с использованием <p:rowEditor/>) для того, чтобы правильно и синхронно работать с оптимистической стратегией блокировки в JPA.

Что было бы правильным способом обойти ситуацию? Отбросить <p:rowEditor/> полностью потребует огромных изменений в существующих приложениях, кстати, что совершенно нежелательно.

+0

Другими словами, объект в ленивой модели данных не обновляется после вызова службы? Изменения не отражаются в этом объекте? – BalusC

+0

Да, модель, поддерживаемая '', не обновляется, если что-то было изменено за спиной, что приводит к тому, что старые/устаревшие значения будут предоставлены при последующих попытках обновить одну и ту же таблицу таблиц данных, если сама таблица не будет перезагружена обновлением например, на текущей странице. – Tiny

+0

Я бы сказал, что обновление модели - это нечто **, которое вы должны сделать. PFdatatable может и не должен знать, что там изменилось. Это может быть, например, что многие другие записи будут обновлены, как хорошо. Одна из причин этого может заключаться в том, что объект в datamodel стал отсоединенным, и перед его обновлением вы его слейте. Вы должны заменить отдельный объект в datamodel на объединенный, а не что-то, что PF может или должен делать. <...> – Kukeltje

ответ

1

В то время как редактирование/обновление строк в <p:dataTable> с использованием <p:rowEditor>, требуется, чтобы синхронизировать изменения вручную в модели данных (LazyDataModel<T>) поддержанного <p:dataTable> после того, как операция обновления завершается успешно.

Один из способов сделать так, чтобы использовать метод getWrappedData() доступных в LazyDataModel<T>, который возвращает данные в настоящее время проводится в модели данных при поддержке данных таблицы в виде java.lang.Object. Это основное использование.

@Named 
@ViewScoped 
public class Bean extends LazyDataModel<Entity> implements Serializable { 

    @Inject 
    private Service service; 
    private static final long serialVersionUID = 1L; 

    public Bean() {} 

    @Override 
    public List<Fruit> load(int first, int pageSize, List<SortMeta> multiSortMeta, Map<String, Object> filters) { 
     setRowCount(service.getRowCount()); 
     // Do something, if necessary. 
     // Turn the List<SortMeta> into another type like a LinkedHashMap<String, String>. 
     return service.getList(first, pageSize, multiSortMeta, filters); 
    } 

    public void onRowEdit(RowEditEvent event) { 
     if (event.getObject() instanceof Entity) { 

      Entity entity = (Entity) event.getObject(); 
      Entity newEntity = service.update(entity); // A new entity from the database. 

      if (newEntity != null) { 

       List<Entity> entities = (List<Entity>) getWrappedData(); 
       int index = entities.indexOf(entity); 

       if (index >= 0) { // The test may be omitted. 
        entities.set(index, newEntity); 
        // Just replace the stale/old entity by a newly updated entity in the database. 
       } 

       // Add an appropriate FacesMessage to indicate a success. 
      } else { 
       // Add an appropriate FacesMessage to indicate a failure. 
      } 
     } else { 
      // Add an appropriate FacesMessage to indicate a failure. 
     } 
    } 
} 

Метод onRowEdit() привязан к слушателю Ajax внутри <p:dataTable>.

<p:ajax event="rowEdit" listener="#{bean.onRowEdit}"/> 

Я не собираюсь принять этот ответ, как там может быть лучший способ сделать это, который я не в курсе. Более полные ответы приветствуются, если таковые имеются.

+0

Вы можете принять его за несколько дней, я думаю. Скорее всего, это не будет более удобным способом, который легко понять.Более общее решение может быть создано с помощью прослушивателей сущностей с помощью механизма обратного вызова и скрыть весь этот код плиты котла. Он может работать даже в общих чертах, если сущности обновляются где-то в другом месте. Но это o/t Я думаю, – Kukeltje

+0

Небольшое предложение: возможно, немного перепишите пример, чтобы 'service.update (...)' был встроен, чтобы люди видели, как происходит слияние. Но спасибо за ответ – Kukeltje

+0

Если объект, о котором идет речь, не имеет никакой связи, то метод 'EJB' service.update (entity) 'содержит только одну строку:' return entityManager.merge (entity); '(используя CMT). Если сущность, однако, содержит ассоциации и каскадное слияние ('CascadeType.MERGE') установлено на стороне владельца отношения, EclipseLink имеет свое [поведение] (http://stackoverflow.com/q/30976896/1391249) это должно быть адекватно обработано. – Tiny

Смежные вопросы