DataViews are used to declare multiple data centric views of your entities required for different use-case (or context) and client.
Why do we need data views?
Imagine the standard use case of an user interface with a search form, result list and detail form. If you think about this rather simple scenario and how many data representations of one and the same data concept (entity) is required you would roughly come up with the following:
one structure to hold the entity attributes the user wants to search for (e.g. ClientSearchView)
one structure containing the condensed entity attributes of the table list (e.g. ClientListView)
another (editable) structure to display more details about the entity (e.g. ClientDetailView)
One could argue that this is a maintenance nightmare and that its simpler to always reuse one superset structure containing all attributes for every use-case. Altough this approach certainly works we are thinking a little bit different about this problem because of the following lessons learned:
ever worked with legacy structures with >100 attributes and you didnt want to read and shuffle all attributes between all your layers everytime? (remote even more worse )
ever wondered why the attribute value is null or if it simply hasn't been fetched from the database by some method?
uneasy feeling seeing the depedencies on your internal (model,data,domain,whatsoever) packages in the external service api because you used it as the return types for your clients
OSIV, lazy loading,layering,...
Therefore we think its best to have a separate structure for each use-case because
there is no more ambiguity about the (value)state of your data
we dont have the maintainenace nightmare since we are using a generative approach (code becomes cheaper now)
we only expose the data the client really needs
no more internals on your external service layers anymore
provides a strict contract with the client of the service about which attributes are available
We call this structure data views because that is what they really
are. A dataview definition starts with the dataview keyword
followed by a name and is shown in the following example.
// dataview of entity 'Customer' including all attributes of Customer
// Note: actually you DONT have to declare such views because the default generator templates create so called default dataviews for each entity
// which look alike the following dataview definition. The name of the default view is always <<EntityName>>View
dataview CustomerView {
Customer.*
}
// dataview of entity 'Customer' with one 'local' attribute and two included customer attributes
dataview CustomerSearchView {
String sortKey
Customer.lastName
Customer.birthDate
}
// dataview of entity 'Customer' which reference anothers dataview
dataview CustomerOrderView {
Customer.lastName
Customer.birthDate
Customer.invoiceAddress<AddressView> // reference mapping with explicit dataview
Customer.billingAddress // reference mapping with the default address dataview i.e. AddressView
}
// default dataview of entity 'Address'
dataview AddressView {
Address.*
}Besides the manually defined dataviews the default
ModelModifier will also create an implicit
DataView (we call this the default
entity DataView) for each entity declaration which
automatically includes all required
simple typed attributes (String,Integer,..) and the to-one relations (or
rather the ForeignKey to the related entity) of the entity from which the
DataView gets derived. The name of this automatically created
DataView is deduced from the entity and by default ends with
a View suffix. (e.g. Entity Customer
will automatically create a DataView named CustomerView) Nevertheless,
sometimes its required to include additional attributes (besides the
aforementioned) in the default DataView which can be easily
achieved by means of manual declaration of a DataView with
the same name as the default DataView. The existence of such a
DataView within the same model file as the corresponding
entity prevents the implicit creation and can be used to modify (only
addition) the structure of the default DataView.
default entity dataview nameCustomerViewentity Customer { String firstName String lastName String ssn Address address Order[] orders } // the existence of a dataview with the prevents the automatically creation of the implicit one dataview { Customer.* // this is the default behaviour and can be omitted if the default fits your need = include all simple type attributes and all to-one entity references // since orders is a many valued (collection) entity reference type its not included in the default DataView and we want to overrule this standard behaviour here Customer.orders }
Note: With the concept of DataViews we support the recommendation from the hibernate best practice chapter given below:
"Use the open session in view pattern, or a disciplined assembly phase to avoid problems with unfetched data: ...Unless you are prepared to hold the persistence context (the session) open across the view rendering process, you will still need an assembly phase. Think of your business methods as having a strict contract with the presentation tier about what data is available"
By default only the identity values of referenced entities are
mapped in dataviews. If the real dataviews of the referenced entities
should be mapped as well one has just to specifiy an additional property
in the dataview definition: the property of the entities reference. Here
is an example, which results in a CustomerOptionalForeignKeyTestDto class
with an addtional property named optionalorder, whose name could be
altered by the as keyword in the dsl, of type
OrderOfCustomerView (the default dataview) instead of only
having a String property holding the identity value of the referenced
OptionalOrder by default:
entity Customer {
id String oid
version Date ^version
String(25) firstName
required = true
title = "First name"
String(25) lastName
required = true
title = "Last name"
composition OrderOfCustomer optionalOrder
oppositeof customer
}
dataview CustomerOptionalForeignKeyTestDto {
Customer.all
Customer.optionalOrder
}
If another dataview should be mapped to than the default dataview,
for instance the OrderOfCustomerLightView, then change the
definition of the dataview like in the following example:
dataview CustomerOptionalForeignKeyTestDto {
Customer.all
Customer.optionalOrder <OrderOfCustomerLightView>
}
For each dataview element one java class is generated and this java class contains all the attributes and references included from the corresponding entity.
Note: There is currently no built-in support to customize this behaviour without to change the default provided workflow and templates.