4.2.3. Views

When retrieving the entities from the database, we often face a question: how to ensure loading of the related entities to desired depth?

For example, you need to display the date and order amount together with the Buyer name in Orders browser, which means that you need to fetch the related Buyer instance. And for Order editor screen, you need to fetch the collection of Items, in addition to that each Item should contain a related Product instance to display its name.

Lazy loading can not help in most cases because data processing is usually performed not in the transaction where the entities were loaded but, for example, on client tier in UI. At the same time it is unacceptable to apply eager fetching by entity annotations as it leads to permanent retrieval of the entire graph of related entities which can be very large.

Another similar problem is the requirement to limit the set of local entity attributes of the loaded graph: for example, some entity can have 50 attributes, including BLOB, but only 10 attributes need to be displayed on the screen. In this case, why should we download 40 remaining attributes from the database, then serialize them and transfer to the client when it does not need them at the moment?

Views mechanism resolves these issues by providing retrieval from database and transmitting to the client entity graphs, limited by depth and by attributes. A view is the descriptor of object graph required on a certain UI screen or data-processing operation.

Views processing is performed in the following way:

  • All relations in the data model are declared with lazy fetching property (fetch = FetchType.LAZY. See Section 4.2.1.2, “Entity Annotations”).

  • In the process of data loading using DataManager the client code provides required view together with JPQL query.

  • The so-called Fetch Plan is produced on the base of the view – this is a special feature of Apache OpenJPA framework lying in the base of ORM layer. Fetch Plan affects the generation of SQL queries to the database: both the list of returned fields and joins with the other tables containing related entities.

  • References, excluded from the Fetch Plan (sometimes this helps to simplify the basic SQL query), are loaded by separate SQL queries. To maintain this process the view-processing mechanism just invokes corresponding attribute reading methods (getters).

  • As a result, when the data loading transaction is finished, the Middleware will contain the object graph, determined by JPQL query and the provided view.

Figure 4.7. View Classes

View Classes

The view is determined by View class instance, where:

  • entityClass – the entity class, for which the view is defined. In other words, it is the “root” of the loaded entities tree.

  • name – the name of the view. It should be either null, or a unique name within all views for the entity.

  • properties – collection of ViewProperty instances, corresponding to the entity attributes which should be loaded.

  • includeSystemProperties – if set, system attributes (included into basic interfaces of BaseEntity and Updatable persistent entities) are automatically included in the view. The system attributes are not explicitly listed in properties but they are included by view processing mechanism depending on the interfaces which are implemented by this entity.

ViewProperty class has the following properties:

  • name – the name of the entity attribute.

  • view – for reference attributes, specifies the view which which will be used to load the related entity.

  • lazy – for reference attributes, indicates that this attribute should not be included into Fetch Plan, but loaded as a separate SQL query, initiated by accessing the attribute. It is important to mention that, if requesting data through DataManager or datasource query, the attribute is loaded anyway, this property affects only the method of fetching. But if the view with lazy attributes is used on the ORM layer, after loading instances they should be passed to EntityManager.fetch() method, otherwise the lazy attributes will not be fetched.

Regardless of the attributes defined in the view, the following attributes are always loaded:

  • id – entity identifier.

  • version – used for optimistic locking of the entities implementing Versioned.

  • deleteTs, deletedBy – used for the entities, implementing SoftDelete.

Attributes, which were not loaded, have null value. By default an attempt to set the value for a not loaded attribute (setter call) for detached entity raises an exception. This behavior can be modified using the application property cuba.allowSetNotLoadedAttributes. If this property is set to true, then setter call will not cause exception, nevertheless the value will not be saved.

Bear in mind that not loaded reference attributes of detached entity, corresponding to external keys (i.е. ManyToOne, OneToOne) can be set to a new non-zero value in any case and the changes will be saved during the subsequent EntityManager.merge().