3.5.3.3. DataContext
Интерфейс DataContext позволяет отслеживать изменения в сущностях, загружаемых на клиентский уровень. Отслеживаемые сущности помечаются как "грязные" при любом изменении их атрибутов, и DataContext сохраняет грязные экземпляры на Middleware при вызове его метода commit().
Внутри DataContext сущность с некоторым идентификатором будет представлена как единственный объект, вне зависимости от того, где и сколько раз она использована в графах других объектов.
Чтобы сущность отслеживалась, её необходимо поместить в DataContext с помощью метода merge(). Если контекст не содержит экземпляра сущности с таким же идентификатором, то контекст создает новый экземпляр и копирует в него состояние переданного. Если контекст уже содержит экземпляр сущности с таким же идентификатором, он копирует в имеющегося состояние переданного и возвращает. Данный механизм позволяет всегда иметь в контексте не более одного экземпляра сущности с конкретным идентификатором.
При помещении сущности в контекст методом merge весь граф объектов с корнем в данной сущности также помещается в контекст. То есть все связанные сущности, включая коллекции, становятся отслеживаемыми.
|  
       Главный принцип использования метода   |  
    
Пример помещения сущности в DataContext:
@Inject
private DataContext dataContext;
private void loadCustomer(Id<Customer, UUID> customerId) {
    Customer customer = dataManager.load(customerId).one();
    Customer trackedCustomer = dataContext.merge(customer);
    customersDc.getMutableItems().add(trackedCustomer);
} 
  Для одного экрана и всех его вложенных фрагментов может существовать только один экземпляр DataContext. Он создаётся автоматически, если в XML-дескрипторе экрана существует элемент <data>.
Элемент <data> может содержать атрибут readOnly="true", в этом случае будет использована специальная "no-op"-реализация, в которой не будут отслеживаться изменения в сущностях и, следовательно, улучшится быстродействие экрана. Экраны просмотра списков, автоматически создаваемые в Studio, по умолчанию имеют read-only data context, поэтому если вам нужно отслеживать изменения и сохранять грязные сущности в браузере, удалите XML-атрибут readOnly="true".
- Родительский DataContext
 -  
    
Сущности
DataContextмогут образовывать отношения предок-потомок. Если у экземпляраDataContextесть родительский контекст, он будет сохранять измененные сущности в своего предка вместо того, чтобы сразу отправлять их на Middleware. Эта особенности позволяет редактировать композитные сущности, где дочерние сущности должны сохраняться только вместе с родительской. Если атрибут сущности снабжён аннотацией @Composition, фреймворк автоматически установит родительский контекст для экрана редактирования этого атрибута, чтобы изменённая сущность атрибута могла быть сохранена только вместе с основной сущностью.Подобное поведение можно легко настроить вручную для любой сущности или экрана.
Если вы программно открываете экран редактирования сущности, который должен сохранять изменения в data context текущего экрана, используйте метод
withParentDataContext()builder’а:@Inject private ScreenBuilders screenBuilders; @Inject private DataContext dataContext; private void editFooWithCurrentDataContextAsParent() { FooEdit fooEdit = screenBuilders.editor(Foo.class, this) .withScreenClass(FooEdit.class) .withParentDataContext(dataContext) .build(); fooEdit.show(); }Если вы открываете простой экран с помощью бина
Screens, определите в нём сеттер, принимающий data context родительского экрана:public class FooScreen extends Screen { @Inject private DataContext dataContext; public void setParentDataContext(DataContext parentDataContext) { dataContext.setParent(parentDataContext); } }Этот метод вы сможете использовать при создании экрана:
@Inject private Screens screens; @Inject private DataContext dataContext; private void openFooScreenWithCurrentDataContextAsParent() { FooScreen fooScreen = screens.create(FooScreen.class); fooScreen.setParentDataContext(dataContext); fooScreen.show(); }Убедитесь, что для родительского data context не задан атрибут
readOnly="true". В противном случае при попытке использовать его как предка другого контекста будет выброшено исключение.