diff --git a/content/en/docs/refguide/modeling/app-explorer/app/app-settings/_index.md b/content/en/docs/refguide/modeling/app-explorer/app/app-settings/_index.md index 76a6f887c3e..60770eba0b1 100644 --- a/content/en/docs/refguide/modeling/app-explorer/app/app-settings/_index.md +++ b/content/en/docs/refguide/modeling/app-explorer/app/app-settings/_index.md @@ -204,6 +204,14 @@ This table presents the results of rounding the input to one digit with the give | -2.5 | -3 | -2 | | -5.5 | -6 | -6 | +### OQL version 2 {#oql-version-2} + +If this option is set to **Yes**, your app will use version 2 of the OQL syntax. This setting must be enabled to use [view entities](/refguide/view-entities/). Make sure your app is ready to use the new syntax before making the switch. + +For more information about the differences, see [OQL Version 2 Features](/refguide/oql-v2/). + +Default: *No* + ### Multiple Sessions per User {#multiple-sessions} If this option is enabled, users can sign in multiple times through different clients (for example, desktop browser and tablet). Otherwise, an existing session for a user is signed out when the user signs in somewhere else. diff --git a/content/en/docs/refguide/modeling/domain-model/_index.md b/content/en/docs/refguide/modeling/domain-model/_index.md index 33081d36176..d58e5060b6e 100644 --- a/content/en/docs/refguide/modeling/domain-model/_index.md +++ b/content/en/docs/refguide/modeling/domain-model/_index.md @@ -13,11 +13,16 @@ The **domain model** describes the information (or data) used by your app in a v The domain model is central to the architecture of your application. Each [module](/refguide/modules/) has its own domain model which describes the data used in that module. All modules in an app can use data from all the domain models within the app. -A domain model consists of [entities](/refguide/entities/) with their relationships to other entities represented by [associations](/refguide/associations/). Entities can be one of three types: +A domain model consists of [entities](/refguide/entities/) with their relationships to other entities represented by [associations](/refguide/associations/). Entities can be one of four types: * Persistable (blue) – entities which hold app information which needs to be held permanently or shared with other end-users of the app (see [Implementation of Persistable Entities](#implementation), below, for information on how these are implemented) * Non-persistable (orange) – entities which hold app information which is needed while the end-user is using the app but can then be thrown away * External (purple) – entities, described in the [Mendix Catalog](/catalog/), which contain data which belongs to another app or service and is needed while the end-user is using the app but isn't stored in the database of the app +* View (green) – entities which are the result of a stored OQL query on persistable entities or other view entities (this feature is in beta) + +{{% alert color="info" %}} +[View entities](/refguide/view-entities/) were introduced in [Studio Pro 10.19](/releasenotes/studio-pro/10.19/) as a beta feature. To enable this feature in your app, set the OQL version to version 2 by clicking **App** > **Settings** > **Runtime**. +{{% /alert %}} You can also add [annotations](/refguide/annotations/) to your domain model to remind yourself, and other team members, how it is to be used. diff --git a/content/en/docs/refguide/modeling/domain-model/entities/_index.md b/content/en/docs/refguide/modeling/domain-model/entities/_index.md index 8ca67b38d97..74e70988210 100644 --- a/content/en/docs/refguide/modeling/domain-model/entities/_index.md +++ b/content/en/docs/refguide/modeling/domain-model/entities/_index.md @@ -26,7 +26,11 @@ The rows in the table are CDs. The type of the two rows is *CD* and this is the ## Types of Entities {#entity-types} -The entity type defines how the data is handled and there are three types: +{{% alert color="info" %}} +View entities were introduced in [Studio Pro 10.19](/releasenotes/studio-pro/10.19/) as a beta feature. +{{% /alert %}} + +The entity type defines how the data is handled and there are four types: * Persistable entity * When an entity is declared persistable, a database table is created for the entity. These type of entities are colored *blue* in the domain model. @@ -34,12 +38,16 @@ The entity type defines how the data is handled and there are three types: * Non-persistable entities are stored in the runtime memory and never get committed to the database. These type of entities are colored *orange* in the domain model. * External entity * External entities represent the link to datasets that are made available through shared data sources registered in Mendix Catalog. These type of entities are colored *purple* in the domain model. +* View entity (beta) + * View entities represent the result sets of stored OQL queries on one or more entities, similar to database viewsn, and are read-only. These entities are colored *green* in the domain model. + +{{< figure src="/attachments/refguide/modeling/domain-model/entities/type-of-entities.jpg" class="no-border" width=="300" >}} -{{< figure src="/attachments/refguide/modeling/domain-model/entities/type-of-entities.jpg" class="no-border" >}} +The structure of persistable, non-persistable, and view entities are defined within your app. This page describes how to add and update persistable and non-persistable entities. For more information on persistable entities, see [Persistability](/refguide/persistability/). -The structure of Persistable and Non-persistable entities are defined within your app. This page describes how to add and update Persistable and Non-persistable entities. For more information on persistable entities, see [Persistability](/refguide/persistability/). +The structure of an external entity is defined in the source system where the underlying data (objects) is stored. For more information on external entities and how to add them to your app, see [External Entities](/refguide/external-entities/). -The structure of an External entity is defined in the source system where the underlying data (objects) is stored. For more information on external entities and how to add them to your app, see [External Entities](/refguide/external-entities/). +View entities are defined by their underlying OQL queries, which run on one or more persistable entities or other view entities. For more information, see [View Entities](/refguide/view-entities/). ## Properties {#properties} diff --git a/content/en/docs/refguide/modeling/domain-model/entities/view-entities/_index.md b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/_index.md new file mode 100644 index 00000000000..7a5b799fb05 --- /dev/null +++ b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/_index.md @@ -0,0 +1,56 @@ +--- +title: "View Entities" +url: /refguide/view-entities/ +weight: 17 +#If moving or renaming this doc file, implement a temporary redirect and let the respective team know they should update the URL in the product. See Mapping to Products for more details. +--- + +{{% alert color="info" %}} This feature is currently in beta. For more information, see [Beta and Experimental Releases](/releasenotes/beta-features/). {{% /alert %}} + +## Introduction + +A view entity represents the result set of a stored [OQL query](/refguide/oql/) and can be used similarly to a [persistable entity](/refguide/persistability/#persistable). This concept is similar to the function of views in general database technology. Whenever a view entity is retrieved via a page or a microflow, the corresponding OQL query executes to fetch the relevant data. Consequently, the result set of a view entity is not stored as a separate table in the database (like a materialized view). Instead, the query runs each time the view entity is accessed, dynamically retrieving the data. + +During modeling, changes to the underlying entities used in the OQL query affect the options available within the query. At runtime, any changes to the data in the underlying entities immediately impact the data available through the view entity. + +View entities can also reference other view entities, allowing for more complex structures and better data organization. + +{{% alert color="info" %}} View entities are read-only. To change the resulting data of a view entity retrieval, the source data should be modified. For this purpose, you can set up a microflow to map a view object to object (or objects) of their corresponding source entity/entities and commit those. {{% /alert %}} + +## Enabling OQL Version 2 + +Your app must use OQL version 2 to use view entities. You can change this setting by clicking **App** > **Settings** > **Runtime** and setting [OQL version 2](/refguide/app-settings/#oql-version-2) to **Yes**. You can also drag a new view entity from the toolbar or **Toolbox** to the domain model, in which Studio Pro will confirm setting the OQL version to 2. + +## Properties + +After adding a view entity, you can specify the OQL query by double-clicking the entity to open the view entity properties dialog: + +{{< figure src="/attachments/refguide/modeling/domain-model/use-view-entities/customer-with-address.png" width="500" >}} + +### General + +The **General** field contains the **OQL editor** and the **Preview data** table. + +The **OQL editor** allows you to write the query that defines this view entity. While writing this query, the editor suggests names of the entities and attributes in your domain model, as well as allowed clauses, operators, and functions. If the query is not valid, a list of validation errors will be displayed underneath the editor with the line and column number of the place where the error was found. + +The resulting names and types of the attributes will be displayed as column headers in the **Preview data** table. You can view the resulting data set of your OQL query by clicking **Run Query**, which enables Studio Pro to retrieve the data from the database that is configured in your app settings. The database type of the active configuration is also listed in the header of the section. To use this functionality, your app must be running. + +{{% alert color="warning" %}} +The **Preview data** table tries to retrieve the data using your OQL query from the running app. This means if you have changed your domain model since you last started the app, you can run into errors when the OQL query uses attributes or entities that do not yet exist in the version of the app that is running. +{{% /alert %}} + +### Access Rules + +When the security level of the app is set to **Production**, the **Access rules** tab becomes available in the view entity properties. + +Assigning write access to an attribute allows the selected module role to edit the in-memory representation of the query result, but not the underlying source entity. The access level set on the view entity is the sole determining factor for whether a role can read or write to it. The access levels of underlying entities are not considered. This is crucial to prevent unintended exposure of data that is restricted at the source entity level. + +Direct writing from the view entity to its source entities is not supported, but you can set up a microflow to retrieve and update the source entities to achieve this functionality. + +### Documentation + +You can add any local information about the view entity in this tab. This is also available to other users working on the app. + +## Using a View Entity + +After creating a view entity in the domain model, it can be used in microflows and pages like any other entity. For more information, see [Use View Entities](/refguide/use-view-entities/). diff --git a/content/en/docs/refguide/modeling/domain-model/entities/view-entities/abstracting-data.md b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/abstracting-data.md new file mode 100644 index 00000000000..5f46e93d4d0 --- /dev/null +++ b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/abstracting-data.md @@ -0,0 +1,54 @@ +--- +title: "Abstracting Data of Add-On Modules" +url: /refguide/abstracting-view-entity-data/ +weight: 100 +--- + +## Introduction + +Add-on modules allow you to abstract your domain model and use view entities to only show the user select details. Add-ons are commonly used for building connectors to other systems, which allows you to abstract away the caching mechanism from outside the module, so users who use the add-on do not have to consider it. + +## Use Case + +For this purpose of this use case, the following domain model is used: + +{{< figure src="/attachments/refguide/modeling/domain-model/view-entities/abstracting-data/domain-model.png" width="500" >}} + +You have a module that manages the inventory and stock of your shop products. You want to export this module so you can reuse it in different projects. To increase security, you do not want to expose the persistable entities, so you want to create view entities that represent the data you want to share outside the module. + +## Create an Add-On Module + +1. Create a new module. +2. Open the module **Settings** and click the **Export** tab. +3. Select **Add-on module** as the module type, then click **OK**. + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/abstracting-data/module-settings.png" width="500" >}} + + With the add-on enabled, you should see an additional configurable property in the documents and other elements of your module called **Export level**. This is set to **Hidden** by default, which means users of your add-on cannot access them. + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/abstracting-data/export-level.png" width="500" >}} + +## Create a View Entity + +You want to make an interface that shows products where you can filter the results by category. Do this by creating a view entity what joins the Product and Category entities. Follow the steps below: + +1. Open your domain model and create a new view entity named *ProductCategoryVE*. +2. Add the following query to the OQL editor: + + ```sql + SELECT + p.ProductId as ProductId + , p.ProductName as ProductName + , p.QuantityPerUnit as QuantityPerUnit + , p.Discontinued as Discontinued + , c.CategoryName as Category + , c.CategoryId as CategoryId + FROM ShopAddOn.Product as p + JOIN p/ShopAddOn.Product_Category/ShopAddOn.Category as c + ``` + +3. Double-click **ProductCategoryVE** and set the export level to **Usable**. + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/abstracting-data/usable.png" width="500" >}} + +4. Export the add-on module by right-clicking it and selecting **Export add-on module package**. diff --git a/content/en/docs/refguide/modeling/domain-model/entities/view-entities/charting-with-view-entities.md b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/charting-with-view-entities.md new file mode 100644 index 00000000000..754c39b093e --- /dev/null +++ b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/charting-with-view-entities.md @@ -0,0 +1,76 @@ +--- +title: "Charting with View Entities" +url: /refguide/charting-with-view-entities/ +weight: 40 +--- + +## Introduction + +You can use view entities to create charts in Studio Pro. This process uses aggregated data. + +## Use Case + +For this purpose of this use case, the following domain model is used: + +{{< figure src="/attachments/refguide/modeling/domain-model/view-entities/charting-with-view-entities/domain-model.png" width="500" >}} + +For example, you own a small business. To keep track of what is being sold, you want to visualize your sales. You want to see how much you make in sales each year, and how each product category contributes to the number. You would like your chart to look similar to the one below: + +{{< figure src="/attachments/refguide/modeling/domain-model/view-entities/charting-with-view-entities/chart-example.png" width="500" >}} + +### Create a View Entity + +Mendix charts do not take associations, so you usually have to take extra steps to use a non-persistable entity as a source. Using view entities is a faster and simpler way to create a chart. + +For the chart, you want the year on the X axis, and the total sales on the Y axis. Create a view entity that groups this data by product category. To do this, follow the steps below: + +1. Open your domain model and create a new view entity named *YearlySalesByCategoryVE*. +2. Add the following query to the OQL editor: + + ```sql + SELECT + CAST(DATEPART(YEAR, o.OrderDate) as INTEGER) as OrderYear + , c.CategoryId as CategoryId + , c.CategoryName as CategoryName + , SUM(ol.Quantity * ol.UnitPrice * (1 - ol.Discount)) as TotalSales + FROM SalesDashboard."Order" as o + JOIN SalesDashboard.OrderLine_Order/SalesDashboard.OrderLine as ol + LEFT JOIN SalesDashboard.OrderLine_Product/SalesDashboard.Product as p + LEFT JOIN SalesDashboard.Product_Category/SalesDashboard.Category as c + GROUP BY c.CategoryId, c.CategoryName, CAST(DATEPART(YEAR, o.OrderDate) as INTEGER) + ``` + +{{% alert color="info" %}} + +View entities allow you to calculate and aggregate the total sales in a single line. You can also take the year by using `DateTime`. +{{% /alert %}} + +### Create the Chart + +Use the new view entity to create a chart. Follow the steps below: + +1. Create a new page or open an existing page. +2. Navigate to the **Toolbox** and add a **Column chart** to the page. +3. Double-click the chart and in the **Data Source** field, click **New**. +4. Configure the chart by filling out the following: + + * Data set - **Multiple series** + * Data source - **YearlySalesByCategoryVE** + * Group by - **CategoryId** + * X axis attribute - **OrderYear** + * Y axis attribute - **TotalSales* + +5. Set the series name to reflect the category name. Do the following: + + * In the **Series name** field, click **Edit** and add **{1}** in the **Template** field. + * In the **Parameters** field, click **New** > **Select** > **CategoryName** > **Select** > **OK**. + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/charting-with-view-entities/series-name.png" width="400" >}} + + The chart should be configured as seen below: + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/charting-with-view-entities/chart-final.png" width="400" >}} + +6. Click **OK** to save. + +7. Run your app locally and you should see the chart populated with your data. diff --git a/content/en/docs/refguide/modeling/domain-model/entities/view-entities/create-pivot-table.md b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/create-pivot-table.md new file mode 100644 index 00000000000..04017f172e3 --- /dev/null +++ b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/create-pivot-table.md @@ -0,0 +1,79 @@ +--- +title: "Create a Pivot Table with View Entities" +url: /refguide/view-entity-pivot-table/ +weight: 70 +--- + +## Introduction + +Use a view entity to create a pivot table. A pivot table is a table that contains a summary of another, more extensive table. + +## Use Case + +For this purpose of this use case, the following domain model is used: + +{{< figure src="/attachments/refguide/modeling/domain-model/view-entities/pivot-table-view-entities/domain-model.png" >}} + +In this example, you run a business and this is your shop's domain model. It includes: + +* A *Product* entity that stores information of all the products sold +* An *Order* entity, which holds information about individual orders +* An *OrderLine* entity, which is a single item in an order + +You want to analyze seasonal sales volumes, which is how much your business makes from sales in each quarter per year. You want your table to resemble the following: + +| Year | TotalSales_Q1 | TotalSales_Q2 | TotalSales_Q3 | TotalSales_Q4| +|------|---------------|---------------|---------------|---------------| +| 1996 | $ … | $ … | $ … | $ … | +| 1997 | $ … | $ … | $ … | $ … | +| 1998 | $ … | $ … | $ … | $ … | +| ... | … | … | … | … | + +## Create a Pivot Table + +Create a view entity that shows each order together with its total value, calculated from the *OrderLine* entity. To do this, follow the steps below: + +1. Open your domain model and add a new view entity. Name this entity *OrderVE*. +2. Add the following query to the OQL editor: + + ```sql + SELECT + o.OrderId as OrderId + , CAST(DATEPART(QUARTER, o.OrderDate) as INTEGER) as OrderQuarter + , CAST(DATEPART(YEAR, o.OrderDate) as INTEGER) as OrderYear + , o.RequiredDate as RequiredDate + , o.ShippedDate as ShippedDate + , SUM(ol.UnitPrice * ol.Quantity * (1 - ol.Discount)) as TotalOrderValue + , SUM(ol.Quantity) as TotalProductCount + , COUNT(*) as UniqueProductCount + FROM Shop."Order" as o + JOIN o/Shop.OrderLine_Order/Shop.OrderLine as ol + GROUP BY o.OrderId, o.OrderDate, o.RequiredDate, o.ShippedDate + ``` + +{{% alert color="info" %}} + +With view entities, you can take the relevant component of `DateTime` as a column using the `DATEPART` function. For more information, see the [`DATEPART` and `DATEDIFF`](/refguide/oql-v2/#date-validations) section of *OQL Version 2 Features*. + +{{% /alert %}} + +3. Add another view entity to the domain model and name it *OrderQuarterlyPivotVE*. This entity will show a table, similar to the format above. +4. Add the following query to the OQL editor: + + ```sql + SELECT + o.OrderYear as OrderYear, + SUM(CASE WHEN o.OrderQuarter = 1 THEN o.TotalOrderValue ELSE 0 END) as TotalSales_Q1, + SUM(CASE WHEN o.OrderQuarter = 2 THEN o.TotalOrderValue ELSE 0 END) as TotalSales_Q2, + SUM(CASE WHEN o.OrderQuarter = 3 THEN o.TotalOrderValue ELSE 0 END) as TotalSales_Q3, + SUM(CASE WHEN o.OrderQuarter = 4 THEN o.TotalOrderValue ELSE 0 END) as TotalSales_Q4 + FROM Shop.OrderVE o + GROUP BY o.OrderYear + ``` + +5. Click **Run Query** to preview the data. + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/pivot-table-view-entities/orderpivotve.png" >}} + +6. Click **OK** to save. +7. Create a page that shows the pivot table by right-clicking the new entity > **Generate overview pages**. \ No newline at end of file diff --git a/content/en/docs/refguide/modeling/domain-model/entities/view-entities/decoupling-apis.md b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/decoupling-apis.md new file mode 100644 index 00000000000..eba7992fa8e --- /dev/null +++ b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/decoupling-apis.md @@ -0,0 +1,49 @@ +--- +title: "Decoupling APIs" +url: /refguide/decoupling-apis/ +weight: 30 +--- + +## Introduction + +Exposing view entities instead of the underlying persistable entity takes away the complexity of the underlying schema. This helps you prevent frequent API changes if the data model changes. It also allows you to consolidate data from multiple tabs in a single API. + +## Use Case + +For this purpose of this use case, the following domain model is used: + +{{< figure src="/attachments/refguide/modeling/domain-model/view-entities/decoupling-apis/domain-model.png" >}} + +For example, you want to make an API call that returns **Products**, and allows you to filter the results by **Category**. + +## Creating a View Entity + +Create a single view entity and expose it as an OData resource. To do this, follow these steps: + +1. Open your domain model and create a view entity called *ProductCategoryVE*. +2. Add the following query to the OQL editor: + + ```sql + SELECT + p.ProductId as ProductId + , p.ProductName as ProductName + , p.QuantityPerUnit as QuantityPerUnit + , p.Discontinued as Discontinued + , c.CategoryName as Category + , c.CategoryId as CategoryId + FROM Shop.Product as p + JOIN p/Shop.Product_Category/Shop.Category as c + ``` + +3. Right-click this entity and select **Publish in OData service**. Name this service *POS_ProductCategory*. +4. Add `ProductId` as a key attribute, then click **OK**. + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/decoupling-apis/key-attribute.png" >}} + + +5. In the **Entity** field, double-click the **ProductId** attribute. +6. Uncheck the box **Can be empty**, then click **OK**. + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/decoupling-apis/can-be-empty.png" >}} + +7. Run your app locally and test the functionality. diff --git a/content/en/docs/refguide/modeling/domain-model/entities/view-entities/multilingual-apps.md b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/multilingual-apps.md new file mode 100644 index 00000000000..c11a8ba015d --- /dev/null +++ b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/multilingual-apps.md @@ -0,0 +1,114 @@ +--- +title: "Multilingual Apps and Translations" +url: /refguide/multilingual-apps/ +weight: 50 +--- + +## Introduction + +Use view entities to create apps that provide translations for your users. + +## Use Case + +For this purpose of this use case, the following domain model is used: + +{{< figure src="/attachments/refguide/modeling/domain-model/view-entities/multilingual-apps/domain-model.png" >}} + +The entity *ProductTranslation* contains a translation of a product’s description to a language indicated by *LanguageCode*. *LanguageCode* is a standard 5-letter language-country code (for example, `en_US`, `nl_NL`, `ko_KR`). + +The descriptions in the default language (in this example, `en_US`) are stored in the *Product* entity, whereas translated descriptions (`nl_NL` and `ko_KR`) are stored in *ProductTranslation*. + +## Create an Overview Page + +To use a view entity that translates languages, ensure your app supports multiple languages. Follow the steps below: + +1. Open your **App Settings** and click the **Languages** tab. +2. Click **Add** and use the drop-down to select the language (or languages) you want to include in your app. +3. Click **OK** > **OK**. + +Combine the languages in the two entities into a single view. To do this, join the *Product* and *ProductTranslation* entities by creating a new view entity. + +1. Open your domain model and add a new view entity named *AllProductTranslationVE*. +2. Add the following query for your entity: + + ```sql + SELECT + p.ProductId as ProductId, + p.ProductName as ProductName, + p.QuantityPerUnit as QuantityPerUnit, + p.Discontinued as Discontinued, + pt.LanguageCode as LanguageCode, + coalesce(pt.Description, p.Description) as Description + FROM Shop.Product p + JOIN p/Shop.ProductTranslation_Product/Shop.ProductTranslation pt + UNION + SELECT + p.ProductId as ProductId, + p.ProductName as ProductName, + p.QuantityPerUnit as QuantityPerUnit, + p.Discontinued as Discontinued, + cast('en_US' as STRING) as LanguageCode, + p.Description as Description + FROM Shop.Product p + ``` + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/multilingual-apps/all-product-translation-ve.png" width="200" >}} + +3. Filter the translation that corresponds to the user’s current language by creating a new view entity. Name this new entity *TranslatedProductVE*. +4. Add the query below to your entity: + + ```sql + SELECT + pt.ProductId as ProductId, + pt.ProductName as ProductName, + pt.QuantityPerUnit as QuantityPerUnit, + pt.Discontinued as Discontinued, + pt.LanguageCode as LanguageCode, + pt.Description as Description + FROM Shop.AllProductTranslationVE pt + LEFT JOIN System.User as u on (u.ID = '[%CurrentUser%]') + LEFT JOIN u/System.User_Language/System.Language as l + WHERE (l.Code = pt.LanguageCode) + ``` + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/multilingual-apps/translated-product-ve.png" width="200" >}} + +Alternatively, you can also combine the view entities into one with a nested query: + +```sql +SELECT + cp.ProductId as ProductId, + cp.ProductName as ProductName, + cp.QuantityPerUnit as QuantityPerUnit, + cp.Discontinued as Discontinued, + cp.Description as Description, + cp.LanguageCode as LanguageCode +FROM +( + SELECT + p.ProductId as ProductId, + p.ProductName as ProductName, + p.QuantityPerUnit as QuantityPerUnit, + p.Discontinued as Discontinued, + pt.LanguageCode as LanguageCode, + coalesce(pt.Description, p.Description) as Description + FROM Shop.Product p + JOIN p/Shop.ProductTranslation_Product/Shop.ProductTranslation pt + UNION + SELECT + p.ProductId as ProductId, + p.ProductName as ProductName, + p.QuantityPerUnit as QuantityPerUnit, + p.Discontinued as Discontinued, + cast('en_US' as STRING) as LanguageCode, + p.Description as Description + FROM Shop.Product p +) as cp + LEFT JOIN System.User as u on (u.ID = '[%CurrentUser%]') + LEFT JOIN u/System.User_Language/System.Language as l +WHERE (l.Code = cp.LanguageCode) +``` + +5. Generate an overview page for the view entity by right-clicking **TranslatedProductVE** > **Generate overview pages**. +6. Open the new page and remove the columns you do not need from the data grid. +7. Run your app locally. You should see the product description in the language that corresponds to the user’s current language. diff --git a/content/en/docs/refguide/modeling/domain-model/entities/view-entities/multitenant-apps.md b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/multitenant-apps.md new file mode 100644 index 00000000000..010b7da963a --- /dev/null +++ b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/multitenant-apps.md @@ -0,0 +1,90 @@ +--- +title: "Multitenant Applications" +url: /refguide/view-entity-multitenant-apps/ +weight: 110 +--- + +## Introduction + +Using view entities in your multitenant applications ensures that users will only see data from the correct tenant they are associated with. + +## Use Case + +For this purpose of this use case, the following domain model is used: + +{{< figure src="/attachments/refguide/modeling/domain-model/view-entities/multitenant-apps/domain-model.png" >}} + +You are developing a project management tool that is used by multiple organizations. You do not want users from one organization to see projects from other organizations. To do this, you want to use a view entity that filters tenant data. + +## Creating a View Entity + +Create a view entity that gets the account and tenant information from the current user. To do this, follow these steps. + +1. Open your domain model and add a view entity named *CurrentUserVE*. +2. Add the following query to the OQL editor: + + ```sql + SELECT + u.UserID as UserID, + u.FullName as FullName, + t.TenantID as TenantID + FROM MultiTenantApp.AppUser u + JOIN u/MultiTenantApp.AppUser_Account/Administration.Account a + JOIN u/MultiTenantApp.AppUser_Tenant/MultiTenantApp.Tenant t + WHERE a.ID = '[%CurrentUser%]' + ``` + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/multitenant-apps/current-user-ve.png" width="200" >}} + + This view entity will always contain one row that contains the information of the current user. + +3. Create another view entity named *ProjectVE*. +4. Add the following query to the OQL editor: + + ```sql + SELECT + p.ProjectID as ProjectID, + t.TenantID as TenantID, + p.Name as Name, + p.Description as Description, + p.StartDate as StartDate, + p.EndDate as EndDate, + p.Status as Status, + p.CreatedAt as CreatedAt, + p.UpdatedAt as UpdatedAt + FROM MultiTenantApp.Project as p + ``` + +5. Generate an overview page by right-clicking this view entity > **Generate overview pages**. +6. Run your app locally. The view entity shows all projects shown in the database. + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/multitenant-apps/project-ve-grid.png" >}} + +### Filter the View Entity + +With these new view entities, you want to only see the projects of a specific tenant that is associated with the current user. This is done by using the CurrentUserVE as a filter. To do this, follow the steps. + +1. Double-click **CurrentUserVE**. +2. In the OQL editor, add three additional lines to the end of the query: + + ```sql + SELECT + p.ProjectID as ProjectID, + t.TenantID as TenantID, + p.Name as Name, + p.Description as Description, + p.StartDate as StartDate, + p.EndDate as EndDate, + p.Status as Status, + p.CreatedAt as CreatedAt, + p.UpdatedAt as UpdatedAt + FROM MultiTenantApp.Project as p + JOIN p/MultiTenantApp.Project_Tenant/MultiTenantApp.Tenant t + JOIN MultiTenantApp.CurrentUserVE cu on (1=1) + WHERE t.TenantID = cu.TenantID + ``` + +3. Generate an overview page by right-clicking this view entity > **Generate overview pages**. +4. Run your app locally. *ProjectVE* only shows projects of the current user's tenant. + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/multitenant-apps/project-ve-grid-2.png" >}} diff --git a/content/en/docs/refguide/modeling/domain-model/entities/view-entities/use-view-entities.md b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/use-view-entities.md new file mode 100644 index 00000000000..bc38bb2016d --- /dev/null +++ b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/use-view-entities.md @@ -0,0 +1,125 @@ +--- +title: "Use View Entities" +url: /refguide/use-view-entities/ +weight: 10 +--- + +## Introduction + +View entities allow you to retrieve, transform, and aggregate your data. They represent a set of stored OQL queries that can be used similarly to [persistable entities]( /refguide/persistability/#persistable). The data that view entities contain is determined when you retrieve the data. + +You can perform operations such as sorting, paging, and filtering using view entities. The entire query is executed by the database, often resulting in faster performance compared to executing multiple independent retrieves. A view entity fetches the data you need from the database and allows data transformation and aggregation. With view entities, you can: + +* Attribute values +* Concatenate attributes +* Calculate aggregates and averages + +## Use Cases + +A view entity can be seen as a named OQL query that behaves like a persistable entity. Because of this, it offers most features that any other entity has. + +### Data Preparation + +When you need data from multiple entities in your widgets, view entities make it faster and simpler to retrieve all necessary data. For example, when using data grids with associations from multiple entities, view entities increase speed and allow for full sorting, pagination, and filtering functions. + +### Charting + +View entities can execute aggregation and calculations required for charts, dashboards, and KPIs within the database, providing the necessary data for your widgets. For more information, see [Charting with View Entities](/refguide/charting-with-view-entities/). + +### API Stability + +To decouple data usage from data storage, especially for APIs, view entities allow you to expose data while keeping your domain model flexible. This ensures API stability for external applications and allows you to change your domain model as needed without affecting the API. For more information, see [Decoupling APIs](/refguide/decoupling-apis/). + +## Creating Maintainable View Entities Using Composability + +Retrieving data from your database can result in very large and complex queries. You may have seen examples of this in SQL, where it is not uncommon to have queries of 100 lines or more. OQL hides some of the complexity, for example, by simplifying joins on associations between entities. + +View entities offer an additional powerful way to improve reusability, readability, and maintainability. You can use them to combine simple queries into more complex ones. A query defines a set of data, which can then be further refined to retrieve more detailed information. A view entity can be also composed of data defined by other view entities. + +For example, the view entity pictured below lists all customers at an organization that are over age 18. The entity includes their full name, age, and delivery and billing addresses. + +{{< figure src="/attachments/refguide/modeling/domain-model/use-view-entities/customer-with-address.png" width="500" >}} + +Age is determined for each customer by calculating the difference in years between the current day and the customer’s date of birth. Another view entity can then count the number of customers that were born in each decade and group them appropriately. + +{{< figure src="/attachments/refguide/modeling/domain-model/use-view-entities/customer-per-decade.png" width="500" >}} + +The original customer view included address information, but most database optimizers will see that this information is not relevant when counting customers by age, so this information is excluded when retrieving the data. However, the information is still present and can be generated, if requested. + +## View Entities and Parameters + +You may have previously used the OQL module or datasets to execute OQL queries. There, you use parameters to configure the query to retrieve the correct data. View entities do not have parameters, but you can dynamically specify what data you want to retrieve. + +Filtering attributes is one way to configure your queries. For example, assume you have an entity with the attributes `FirstName` and `LastName`. In a view entity, you combine both the first name and last name into a `FullName` attribute. When you select from this entity, you can specify an XPath expression that limits the data on the full attribute name. + +Alternatively, you can store the parameter value in the database, then use that value in your view entity. For example, the image below is of a view entity that returns the data of the *Product* entity in the language of the current user. + +{{< figure src="/attachments/refguide/modeling/domain-model/use-view-entities/product-language.png" width="500" >}} + +This is done by joining an entity that has all the necessary translations and filtering it by the language of the current user. Coalesce is used to return the default language in case there is no translation is available. + +This approach can also be useful for multitenant applications. If you have a multitenant system where every user has a tenant ID, you can ensure through view entities that any data that is tenant-specific will only return data for the tenant of the current user. For more information, see [Multitenant Applications](/refguide/view-entity-multitenant-apps/). + +## Data Security + +Use the [`WHERE` clause]( /refguide/oql-expressions/) of a view entity to ensure only data that should be available to the user is returned. This is an alternative to the access rules you can have on both persistable entities and view entities. + +Persistable entity access rules are not applied when using view entities. Instead, you must specify the access rules. You can define what users have access to while still allowing access to aggregated data. For example, you may want to know how many employees are part of each department of a company. However, you should not be able to see the detailed information of each employee. View entities allow you to give a user access to specific employee data without revealing sensitive information. + +### Multi-Tenant Security + +In the following example, a view entity is used to implement multi-tenant security. The view entity *CustomersVE* only returns the customers that belong to the tenant of the current user. Any additional view entity that uses *CustomersVE* instead of the persistable entity *Customer* will only get data belonging to the tenant of the user. + +{{< figure src="/attachments/refguide/modeling/domain-model/use-view-entities/active-tenant.png" width="500" >}} + +Instead of joining with the `[%CurrentUser%]` expression, this example joins with a view entity that only returns one object: the current user and related details, such active language and tenant ID. This simplifies use of user information for other view entities. + +{{< figure src="/attachments/refguide/modeling/domain-model/use-view-entities/current-user.png" width="500" >}} + +## Performance + +When working with large amounts of data, using the database optimizer to get required information from your database is usually faster than processing in the application itself. A database knows the data’s characteristics, and therefore can find the fastest path to access the data. It can also aggregate data in the database, minimizing unnecessary data movement. + +In the example above where customers are counted in age brackets, the query result contains approximately 10 objects. To determine these 10 objects, the database may need to process thousands or even millions of objects. A database can do this more efficiently if all objects are read into a Mendix Runtime for aggregation. + +## Understanding Query Plans + +To understand the performance impact of database queries, it is best to determine the query plan the database creates. A query plan explains how the database will execute your query. For a query, the fastest way to retrieve data can be different for every call, as it depends on many factors, such as: + +* The query +* Parameters +* The size of your data +* Distribution of your data +* Availability of indexes that suit your query and parameters + +Below, you see how the data for customers per age bracket is fetched by a database (read bottom up): + +{{< figure src="/attachments/refguide/modeling/domain-model/use-view-entities/query-plans.png" >}} + +The database follows the below process: + +1. It reads through all customer records and determines if the customer is older than 18. It typically reads through all records, but often uses an index to increase efficiency. +2. It sorts the data by age bracket. +3. It groups and counts the customers in every bracket. +4. It sorts the results again by the number of customers per bracket, in descending order. + +Even though the query is using a view that also includes address information, the database ignores this information, as it is not relevant when counting customers by age. + +If you set the `DataStorage_QueryPlan` log node to Trace, you see the query plan for your queries in the Mendix Runtime log. + +## Read More + +For more information on how to enable view entities in your app, see [View Entities]( /refguide/view-entities/) and [OQL]( /refguide/oql/). + +For specific use case scenarios, see the following: + +* [Creating Overview Pages](/refguide/view-entity-overview-pages/) +* [Decoupling APIs](/refguide/decoupling-apis/) +* [Charting with View Entities](/refguide/charting-with-view-entities/) +* [Multilingual Apps and Translations](/refguide/multilingual-apps/) +* [View Archived Data](/refguide/view-archived-data/) +* [Create a Pivot Table with View Entities](/refguide/view-entity-pivot-table/) +* [Data Versioning with View Entities](/refguide/view-entity-data-versioning/) +* [Exporting Data with View Entities](/refguide/view-entity-expport-data/) +* [Abstracting Data of Add-On Modules](/refguide/abstracting-view-entity-data/) +* [Multitenant Applications](/refguide/view-entity-multitenant-apps/) diff --git a/content/en/docs/refguide/modeling/domain-model/entities/view-entities/view-archived-data.md b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/view-archived-data.md new file mode 100644 index 00000000000..bca4641c2cb --- /dev/null +++ b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/view-archived-data.md @@ -0,0 +1,49 @@ +--- +title: "View Archived Data" +url: /refguide/view-archived-data/ +weight: 60 +--- + +## Introduction + +View entities can be used to make a consolidated view of archived historical and active data, allowing access to both datasets in a single query, while keeping track of its origins. By consolidating, the active entity is smaller, enabling faster data retrieval and improving app performance. + +## Use Case + +For this purpose of this use case, the following domain model is used: + +{{< figure src="/attachments/refguide/modeling/domain-model/view-entities/view-archived-data/domain-model.png" width="400" >}} + +Create a view entity that contains the columns of the *ActiveProducts* and *DiscontinuedProducts* entities, as well as an additional column, *Archived*. The *Archived* column will indicate the origin table of each product. + +## Create a View Entity + +1. Open your domain model and add a new view entity named *AllProductsVE*. +2. Add the following query to your entity: + + ```sql + SELECT + ap.ProductId as ProductId, + ap.ProductName as ProductName, + ap.QuantityPerUnit as QuantityPerUnit, + ap.Category as Category, + ap.Price as Price, + cast(FALSE as BOOLEAN) as Archived + FROM Shop.ActiveProducts ap + UNION + SELECT + dp.ProductId as ProductId, + dp.ProductName as ProductName, + dp.QuantityPerUnit as QuantityPerUnit, + dp.Category as Category, + dp.Price as Price, + cast(TRUE as BOOLEAN) as Archived + FROM Shop.DiscontinuedProducts dp + ``` + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/view-archived-data/all-products-ve.png" width="200" >}} + +3. Generate an overview page for the view entity by right-clicking **AllProductsVE** > **Generate overview pages**. +4. Run your app locally and view the new data grid. + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/view-archived-data/data-grid.png" >}} diff --git a/content/en/docs/refguide/modeling/domain-model/entities/view-entities/view-entity-data-versioning.md b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/view-entity-data-versioning.md new file mode 100644 index 00000000000..783b02a8f3c --- /dev/null +++ b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/view-entity-data-versioning.md @@ -0,0 +1,76 @@ +--- +title: "Data Versioning with View Entities" +url: /refguide/view-entity-data-versioning/ +weight: 80 +--- + +## Introduction + +View entities allow you to work with versioned data. In this example, you will implement versioned data within a domain model. + +## Use Case + +For this purpose of this use case, the following domain model is used: + +{{< figure src="/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/domain-model.png" width="500" >}} + +The domain model above is for an ordering system of a shop. The entities contain the following: + +* *OrderInfo* - information about an order, such as the fulfillment deadline +* *OrderLine* - information about purchased items, such as price or quantity +* *Customer* - information about the purchasing customer +* *OrderUpdate* - information about the status of an order, such as when the order ships or is delivered; a new row is added every time an order status changes + +An advantage of separating *OrderUpdate* from *OrderLine* is that it is easier to keep track of the order history. You can create an entity that includes information from both entities, but it works on the assumption that the workflow remains the same with each order (for example, order placed > order processed > order shipped). However, this may make it difficult to see other statuses, such as which orders have been processed. To avoid this, use a view entity to implement data versioning. + +## Data Versioning + +To view the latest status of an order, follow the steps below: + +1. Open your domain model and add a view entity named *LatestOrderStatusVE*. +2. Add the following query to the OQL editor: + + ```sql + SELECT + o.OrderId as OrderId, + o.RequiredDate as RequiredDate, + u.OrderStatus as OrderStatus, + u.UpdateDate as UpdateDate + FROM Shop.OrderInfo o + JOIN o/Shop.OrderUpdate_OrderInfo/Shop.OrderUpdate u + JOIN ( + SELECT + u.OrderId as OrderId, + MAX(u.UpdateDate) as UpdateDate + FROM Shop.OrderUpdate u + GROUP BY u.OrderId + ) latest ON (latest.OrderId = o.OrderId AND latest.UpdateDate = u.UpdateDate) + ``` + +{{% alert color="info" %}} + +The above query is a nested query. It retrieves information from the *OrderInfo* table, then joins it with the *OrderUpdate* table. The result is a table with every update of every order. If you are only interested in the latest update of each table, retrieve the latest date an order is updated using `MAX(u.UpdateDate)` and combine it with the previous `JOIN`. + +For more information on different OQL clauses, see [OQL Version 2 Features](/refguide/oql-v2/). + +{{% /alert %}} + +The final result is a list with only the latest update of each order: + +{{< figure src="/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/entity-properties.png" width="500" >}} + +{{< figure src="/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/data-grid.png" width="500" >}} + +## Order Status on Specific Date + +Another advantage of data versioning is that you can take a snapshot of the order status on any given date. For example, if you want to know the status of orders on 8/17/1997, add the following line at the end of your existing query: + +```sql +WHERE u.UpdateDate < CAST('1997/08/17' as DATETIME) +``` + +This addition retrieves the order status for one specific date: + +{{< figure src="/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/entity-properties-2.png" width="500" >}} + +{{< figure src="/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/data-grid-2.png" width="500" >}} \ No newline at end of file diff --git a/content/en/docs/refguide/modeling/domain-model/entities/view-entities/view-entity-export-data.md b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/view-entity-export-data.md new file mode 100644 index 00000000000..8b302e307ae --- /dev/null +++ b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/view-entity-export-data.md @@ -0,0 +1,72 @@ +--- +title: "Exporting Data with View Entities" +url: /refguide/view-entity-expport-data/ +weight: 90 +--- + +## Introduction + +Use view entities to export data from your domain model with JSON. + +## Use Case + +For this purpose of this use case, the following domain model is used: + +{{< figure src="/attachments/refguide/modeling/domain-model/view-entities/exporting-data/domain-model.png" width="400" >}} + +The domain model contains two entities that store customer data and their associated delivery and billing addresses. + +You want to export a report of customer information in JSON format. The report should contain the customer's billing address and delivery address, all contained in the same field. This can be done in one view entity, rather than having to decide the logic for a Customer-Address association in a microflow. + +## Transform and Export Data with JSON + +Create a view entity to join the customer and address tables. To do this, follow the steps below: + +1. Create a view entity and name it *CustomerVE*. +2. Add the following query to the OQL editor: + + ```sql + SELECT + c.CustomerId as CustomerID, + c.CompanyName as Company, + (c.FirstName + ' ' + c.LastName) as FullName, + c.Phone as Phone, + c.Fax as Fax, + (ba.Address + ', ' + ba.City + ' ' + ba.PostalCode + ', ' + ba.Country) as BillingAddress, + (da.Address + ', ' + da.City + ' ' + da.PostalCode + ', ' + da.Country) as DeliveryAddress + FROM Shop.Customer c + LEFT JOIN c/Shop.BillingAddress/Shop.Address ba + LEFT JOIN c/Shop.DeliveryAddress/Shop.Address da + ``` + +3. Click **Run Query** to view the data. Then, click **OK**. + +### Create a JSON Structure + +Create a JSON structure that represents the customer entity. To do this, follow these steps: + +1. Right-click your module and select **Add other** > **JSON structure**. +2. Create an example snippet of the JSON object. + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/exporting-data/json-structure.png" width="500" >}} + +3. Click **Refresh**, then click **OK** to save. + +### Create an Export Mapping + +1. Right-click your module and select **Add other** > **Export mapping**. Name this mapping *EM_Customer*. +2. In the **Schema source** field, select the JSON structure you created in the previous section. +3. In the **Schema elements** field, select **Check all**, then click **OK**. + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/exporting-data/export-mapping-data.png" width="500" >}} + +4. In the Integration pane, open the **Connectors** tab. +5. Drag **CustomerVE** to the export mapping document. + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/exporting-data/connectors-pane.png" width="500" >}} + +6. Map the CustomerVE attributes to their corresponding schema field. + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/exporting-data/mapping.png" width="500" >}} + +7. Click **OK** to save. \ No newline at end of file diff --git a/content/en/docs/refguide/modeling/domain-model/entities/view-entities/view-entity-overview-pages.md b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/view-entity-overview-pages.md new file mode 100644 index 00000000000..3f4e84b47ec --- /dev/null +++ b/content/en/docs/refguide/modeling/domain-model/entities/view-entities/view-entity-overview-pages.md @@ -0,0 +1,276 @@ +--- +title: "Creating Overview Pages" +url: /refguide/view-entity-overview-pages/ +weight: 20 +--- + +## Introduction + +Use view entities to show data across multiple associated entities. + +## Use Case + +For this purpose of this use case, the following domain model is used: + +{{< figure src="/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/domain-model.png" >}} + +In this scenario, you will create an overview page that lists each product in a [data grid]( /appstore/modules/data-grid-2/), including information about its category and supplier. With view entities, you do not have to manage associations when showing the data in a data grid. This means that all fields are filterable and sortable, which allows for higher performance and flexibility. + +{{% alert color="info" %}} + +You must have an existing database containing data prior to using a view entity. Do this by generating overview pages using the entities in the above domain model, then adding sample data. + +{{% /alert %}} + +## Create a Data Grid + +Create a view entity that combines only the relevant attributes of the entities *Product*, *Supplier*, and *Category*. To do this, follow these steps: + +1. Open your domain model and add a new view entity. +2. Name the view entity *ProductOverviewVE*. +3. Add the following query to the OQL editor: + + ```sql + SELECT + p.ProductId as ProductId, + p.ProductName as ProductName, + p.QuantityPerUnit as QuantityPerUnit, + p.Discontinued as Discontinued, + s.CompanyName as Supplier, + c.CategoryName as Category + FROM Shop.Product as p + JOIN p/Shop.Product_Supplier/Shop.Supplier as s + JOIN p/Shop.Product_Category/Shop.Category as c + ``` +{{% alert color="info" %}} + +This query uses OQL to take the four attributes of each product and combines them with the associated supplier and category. If there is no supplier or category, the product will not be included. For more information, see [OQL Expressions](/refguide/oql-expressions/). + +{{% /alert %}} + +4. Click **OK**. The view entity is added to your domain model. + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/product-overview-ve.png" width="150" >}} + +5. Generate an overview page by right-clicking the view entity > **Generate overview pages**. + +6. Add the new overview page to the navigation. + +7. Run your app locally, then click **View App**. You should see the data grid populated with the information that was previously added. + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/live-data-grid.png" >}} + +{{% alert color="info" %}} + +In the new data grid created by *ProductOverviewVE*, the **Edit** button is not functional. You can hide or remove this button, or use it to [add a new product](#add-product) to the grid. + +{{% /alert %}} + +## Alternative to Calculated Attributes + +You can use view entities to search and sort items, as well as hold the calculated attribute (or Total Value). This is only calculated once, unlike a non-persistable entity, where it is calculated each time the object is accessed. + +For example, the *OrderLine* entity represents a single entry in an order. It has the following attributes: + +* `UnitPrice` +* `Quantity` +* `Discount` + +### Get Total Value + +Suppose you want to get the total value of each order line, which is given by the formula `Total = UnitPrice * Quantity * (1 – Discount)`. To do this, follow these steps: + +1. Create a view entity and name it *OrderLineWithTotalVE*. +2. Add the following query to the OQL editor: + + ```sql + SELECT + ol.OrderLineId as OrderLineId, + ol.Quantity as Quantity, + ol.UnitPrice as UnitPrice, + ol.Discount as Discount, + (ol.Quantity * ol.UnitPrice * (1 - ol.Discount)) as Total + FROM Shop.OrderLine ol + ``` + +3. Generate an overview page by right-clicking the view entity > **Generate overview pages**. +4. Add the new overview page to the navigation. +5. Run your app locally, then click **View App**. Use this view entity in a data grid to show the total value. + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/total-value.png" >}} + +### Join OrderLine and Order Entities + +You can calculate the total value of an order by joining the `OrderLine` and `Order`tables. To do this, follow the steps below: + +1. Create a new view entity and name it *OrderWithTotalValueVE*. +2. Add the following query to the OQL editor: + + ```sql + SELECT + o.OrderId as OrderId, + o.OrderDate as OrderDate, + o.RequiredDate as RequiredDate, + o.ShippedDate as ShippedDate, + SUM(ol.UnitPrice * ol.Quantity * (1 - ol.Discount)) as TotalOrderValue, + SUM(ol.Quantity) as TotalProductCount, + COUNT(*) as UniqueProductCount + FROM Shop."Order" as o + JOIN o/Shop.OrderLine_Order/Shop.OrderLine as ol + GROUP BY o.OrderId, o.OrderDate, o.RequiredDate, o.ShippedDate + ``` + +This results in a view entity that shows the total value of every order. + +{{% alert color="info" %}} +Notice the quotation marks in `Shop.”Order”`. This is because `Order` is a reserved keyword in OQL. To avoid ambiguity, quotation marks are put around the word. +{{% /alert %}} + +3. Generate an overview page by right-clicking the view entity > **Generate overview pages**. +4. Add the new overview page to the navigation. +5. Run your app locally, then click **View App**. This results in a view entity that shows the total value of every order. + +## Update Underlying Persistent Entities + +On the Product overview page above, there is no button to add or modify a product. This functionality can be added to a view entity to update its corresponding persistable entity object. + +1. Create a microflow and name it *ACT_UpdateProduct*. +2. Add a parameter and in the entity field and select **ProductOverviewVE**. +3. Add a [retrieve](/refguide/retrieve/) activity. In this activity, retrieve a *Product* object from the database. Configure the activity with the following details: + + * Use the following XPath constraint: + + ``` + [(ProductId = $ProductOverviewVE/ProductId)] + ``` + + * In the Options field, set Range to **First** + +4. Add a [Change Object]( /refguide/change-object/) activity. Configure the activity by adding the attributes of `Product` to reflect those of `ProductOverviewVE` + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/change-object.png" >}} + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/product-overview-microflow.png" >}} + +5. Open the ProductOverviewVE_NewEdit page that was generated by *ProductOverviewVE*. +6. Remove the Product ID, Supplier, and Category fields. +7. Double-click the **Save** button and in the **On click** field, select **Call a microflow**. +8. Under Microflow, click **Select** > **ACT_UpdateProduct**. +9. Click **OK**. +10. Open the ProductOverviewVE_Overview page. +11. Add a button to the grid and link it to the ProductOverviewVE_NewEdit page. + +Once these steps are complete, run your app locally and test the functionality. + +## Update Associated Product Category and Supplier + +Add the capability to update a product’s associated category and supplier. To do this, follow these steps: + +1. Open your domain model and double-click **ProductOverviewVE**. +2. Add `CategoryId` and `SupplierId` by using the following query in the OQL editor: + + ```sql + SELECT + p.ProductId as ProductId, + p.ProductName as ProductName, + p.QuantityPerUnit as QuantityPerUnit, + p.Discontinued as Discontinued, + s.CompanyName as Supplier, + c.CategoryName as Category, + s.SupplierId as SupplierId, + c.CategoryId as CategoryId + FROM Shop.Product as p + JOIN p/Shop.Product_Supplier/Shop.Supplier as s + JOIN p/Shop.Product_Category/Shop.Category as c + ``` + +3. Create two more view entities that retrieve ID and names from the Supplier and Category tables and name them *SupplierNamesVE* and *CategoryNamesVE*. Add the following queries into the OQL editor. Add one to each entity: + + ```sql + SELECT + s.SupplierId as SupplierId, + s.CompanyName as SupplierName + FROM Shop.Supplier s + ``` + + ```sql + SELECT + c.CategoryId as CategoryId, + c.CategoryName as CategoryName + FROM Shop.Category c + ``` + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/supplier-and-category-ve.png" width="400" >}} + +4. On the ProductOverviewVE_NewEdit page, add a combo box inside the data view. Include the following information: + + * In the **Data source** field, select **Database** + * Under **Selectable objects**, click **Edit** > **Entity (path)** > **CategoryNamesVE** > **Select** + * Under **Caption**, select **CategoryNames** + * Under **Value**, select **CategoryId** + * Under **Target attribute**, select **Category** + +5. Add another combo box and repeat the above steps for the *SupplierNameVE* entity. + +The final data view should look like this: + +{{< figure src="/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/product-overview-page.png" >}} + +## Update Product Microflow {#update-microflow} + +Once the Product page is complete, update the related microflow. To do this, follow the steps below: + +1. Open the **ACT_UpdateProduct** microflow. +2. Add a Retrieve activity after the existing Retrieve product activity. +3. Retrieve a Category object from the database. Configure the activity using the following details: + + * Use the following XPath constraint: + + ``` + [CategoryId = $ProductOverviewVE/CategoryId] + ``` + + * In the Range field, select **First** + +4. Add another Retrieve activity to retrieve the Supplier object. Configure the activity using the following details: + + * Use the following XPath constraint: + + ``` + [SupplierId = $ProductOverviewVE/SupplierId] + ``` + + * In the Range field, select **First** + +5. In the existing Change Product activity, click **New** and add the Category and Supplier associations and set them to their corresponding objects. + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages//update-product-microflow.png" >}} + +When you run your app, you should now be able to update the product’s category and supplier. + +## Add a New Product {#add-product} + +You can use a view entity to add a new product into the existing database. Follow the steps below: + +1. Create a new microflow and name it *ACT_CreateProduct* +2. Add a Create object activity to create a *Product* (the persistable entity) object. Leave all the attributes blank. +3. Check the Commit checkbox. +4. Place another Retrieve object activity after the previous activity. +5. Retrieve `ProductOverviewVE` that corresponds to the new `Product` object. Configure it with the following details: + + * Use the following XPath constraint: + + ``` + [(ProductId = $NewProduct/ProductId)] + ``` + + * In the Range field, select **First** + +6. Add a Show page activity and set it to open the Edit Product page. Use `NewProductVE` as the page parameter. + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/create-product-microflow.png" >}} + +7. Open the ProductOverviewVE_Overview page and add a new button named *New*. +8. In the new button, under **On click**, select **CreateProduct**. + + {{< figure src="/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/nanoflow-data.png" >}} diff --git a/static/attachments/refguide/modeling/domain-model/use-view-entities/active-tenant.png b/static/attachments/refguide/modeling/domain-model/use-view-entities/active-tenant.png new file mode 100644 index 00000000000..b2cda877bad Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/use-view-entities/active-tenant.png differ diff --git a/static/attachments/refguide/modeling/domain-model/use-view-entities/current-user.png b/static/attachments/refguide/modeling/domain-model/use-view-entities/current-user.png new file mode 100644 index 00000000000..e2fb032ac70 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/use-view-entities/current-user.png differ diff --git a/static/attachments/refguide/modeling/domain-model/use-view-entities/customer-per-decade.png b/static/attachments/refguide/modeling/domain-model/use-view-entities/customer-per-decade.png new file mode 100644 index 00000000000..f680d991c91 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/use-view-entities/customer-per-decade.png differ diff --git a/static/attachments/refguide/modeling/domain-model/use-view-entities/customer-with-address.png b/static/attachments/refguide/modeling/domain-model/use-view-entities/customer-with-address.png new file mode 100644 index 00000000000..9b7c2a4c283 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/use-view-entities/customer-with-address.png differ diff --git a/static/attachments/refguide/modeling/domain-model/use-view-entities/product-language.png b/static/attachments/refguide/modeling/domain-model/use-view-entities/product-language.png new file mode 100644 index 00000000000..8af568fbb3c Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/use-view-entities/product-language.png differ diff --git a/static/attachments/refguide/modeling/domain-model/use-view-entities/query-plans.png b/static/attachments/refguide/modeling/domain-model/use-view-entities/query-plans.png new file mode 100644 index 00000000000..399f4147745 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/use-view-entities/query-plans.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/abstracting-data/domain-model.png b/static/attachments/refguide/modeling/domain-model/view-entities/abstracting-data/domain-model.png new file mode 100644 index 00000000000..9c5876e6811 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/abstracting-data/domain-model.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/abstracting-data/export-level.png b/static/attachments/refguide/modeling/domain-model/view-entities/abstracting-data/export-level.png new file mode 100644 index 00000000000..1a0fcfe2ea7 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/abstracting-data/export-level.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/abstracting-data/module-settings.png b/static/attachments/refguide/modeling/domain-model/view-entities/abstracting-data/module-settings.png new file mode 100644 index 00000000000..7134135398d Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/abstracting-data/module-settings.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/abstracting-data/usable.png b/static/attachments/refguide/modeling/domain-model/view-entities/abstracting-data/usable.png new file mode 100644 index 00000000000..2fdd04fc03a Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/abstracting-data/usable.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/charting-with-view-entities/chart-example.png b/static/attachments/refguide/modeling/domain-model/view-entities/charting-with-view-entities/chart-example.png new file mode 100644 index 00000000000..6e7d66e3b46 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/charting-with-view-entities/chart-example.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/charting-with-view-entities/chart-final.png b/static/attachments/refguide/modeling/domain-model/view-entities/charting-with-view-entities/chart-final.png new file mode 100644 index 00000000000..31d48dba81f Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/charting-with-view-entities/chart-final.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/charting-with-view-entities/domain-model.png b/static/attachments/refguide/modeling/domain-model/view-entities/charting-with-view-entities/domain-model.png new file mode 100644 index 00000000000..33ad82b2ea5 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/charting-with-view-entities/domain-model.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/charting-with-view-entities/edit-column-chart.png b/static/attachments/refguide/modeling/domain-model/view-entities/charting-with-view-entities/edit-column-chart.png new file mode 100644 index 00000000000..694032b0e3c Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/charting-with-view-entities/edit-column-chart.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/charting-with-view-entities/series-name.png b/static/attachments/refguide/modeling/domain-model/view-entities/charting-with-view-entities/series-name.png new file mode 100644 index 00000000000..7ad07c9297f Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/charting-with-view-entities/series-name.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/change-object.png b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/change-object.png new file mode 100644 index 00000000000..0afcc30ff8c Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/change-object.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/create-product-microflow.png b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/create-product-microflow.png new file mode 100644 index 00000000000..e72955c8832 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/create-product-microflow.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/domain-model.png b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/domain-model.png new file mode 100644 index 00000000000..bf5b17f7b4e Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/domain-model.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/live-data-grid.png b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/live-data-grid.png new file mode 100644 index 00000000000..3dff94e11fd Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/live-data-grid.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/nanoflow-data.png b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/nanoflow-data.png new file mode 100644 index 00000000000..47fd7ba0d0d Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/nanoflow-data.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/product-overview-microflow.png b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/product-overview-microflow.png new file mode 100644 index 00000000000..f7f09bf1346 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/product-overview-microflow.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/product-overview-page.png b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/product-overview-page.png new file mode 100644 index 00000000000..5e279e44415 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/product-overview-page.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/product-overview-ve.png b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/product-overview-ve.png new file mode 100644 index 00000000000..f8498df5d83 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/product-overview-ve.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/supplier-and-category-ve.png b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/supplier-and-category-ve.png new file mode 100644 index 00000000000..aefc77844da Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/supplier-and-category-ve.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/total-value.png b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/total-value.png new file mode 100644 index 00000000000..c36705bdc34 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/total-value.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/update-product-microflow.png b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/update-product-microflow.png new file mode 100644 index 00000000000..0abb37af146 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/create-overview-pages/update-product-microflow.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/decoupling-apis/can-be-empty.png b/static/attachments/refguide/modeling/domain-model/view-entities/decoupling-apis/can-be-empty.png new file mode 100644 index 00000000000..05e4eb671a5 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/decoupling-apis/can-be-empty.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/decoupling-apis/domain-model.png b/static/attachments/refguide/modeling/domain-model/view-entities/decoupling-apis/domain-model.png new file mode 100644 index 00000000000..bf5b17f7b4e Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/decoupling-apis/domain-model.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/decoupling-apis/key-attribute.png b/static/attachments/refguide/modeling/domain-model/view-entities/decoupling-apis/key-attribute.png new file mode 100644 index 00000000000..cbbd184658f Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/decoupling-apis/key-attribute.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/exporting-data/connectors-pane.png b/static/attachments/refguide/modeling/domain-model/view-entities/exporting-data/connectors-pane.png new file mode 100644 index 00000000000..9fcf09180a0 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/exporting-data/connectors-pane.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/exporting-data/domain-model.png b/static/attachments/refguide/modeling/domain-model/view-entities/exporting-data/domain-model.png new file mode 100644 index 00000000000..78559499a62 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/exporting-data/domain-model.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/exporting-data/export-mapping-data.png b/static/attachments/refguide/modeling/domain-model/view-entities/exporting-data/export-mapping-data.png new file mode 100644 index 00000000000..1813fa2e66c Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/exporting-data/export-mapping-data.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/exporting-data/json-structure.png b/static/attachments/refguide/modeling/domain-model/view-entities/exporting-data/json-structure.png new file mode 100644 index 00000000000..5f9bd71c287 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/exporting-data/json-structure.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/exporting-data/mapping.png b/static/attachments/refguide/modeling/domain-model/view-entities/exporting-data/mapping.png new file mode 100644 index 00000000000..523cacdabeb Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/exporting-data/mapping.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/multilingual-apps/all-product-translation-ve.png b/static/attachments/refguide/modeling/domain-model/view-entities/multilingual-apps/all-product-translation-ve.png new file mode 100644 index 00000000000..3ebd0116986 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/multilingual-apps/all-product-translation-ve.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/multilingual-apps/domain-model.png b/static/attachments/refguide/modeling/domain-model/view-entities/multilingual-apps/domain-model.png new file mode 100644 index 00000000000..bdab397cbc4 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/multilingual-apps/domain-model.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/multilingual-apps/translated-product-ve.png b/static/attachments/refguide/modeling/domain-model/view-entities/multilingual-apps/translated-product-ve.png new file mode 100644 index 00000000000..9c12d770267 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/multilingual-apps/translated-product-ve.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/multitenant-apps/current-user-ve.png b/static/attachments/refguide/modeling/domain-model/view-entities/multitenant-apps/current-user-ve.png new file mode 100644 index 00000000000..9139cde5a5e Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/multitenant-apps/current-user-ve.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/multitenant-apps/domain-model.png b/static/attachments/refguide/modeling/domain-model/view-entities/multitenant-apps/domain-model.png new file mode 100644 index 00000000000..c3ec0b24e4b Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/multitenant-apps/domain-model.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/multitenant-apps/project-ve-grid-2.png b/static/attachments/refguide/modeling/domain-model/view-entities/multitenant-apps/project-ve-grid-2.png new file mode 100644 index 00000000000..66a7ca5be7f Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/multitenant-apps/project-ve-grid-2.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/multitenant-apps/project-ve-grid.png b/static/attachments/refguide/modeling/domain-model/view-entities/multitenant-apps/project-ve-grid.png new file mode 100644 index 00000000000..ee496fbc05d Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/multitenant-apps/project-ve-grid.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/pivot-table-view-entities/domain-model.png b/static/attachments/refguide/modeling/domain-model/view-entities/pivot-table-view-entities/domain-model.png new file mode 100644 index 00000000000..dab557a8acd Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/pivot-table-view-entities/domain-model.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/pivot-table-view-entities/orderpivotve.png b/static/attachments/refguide/modeling/domain-model/view-entities/pivot-table-view-entities/orderpivotve.png new file mode 100644 index 00000000000..cdf14851463 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/pivot-table-view-entities/orderpivotve.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/view-archived-data/all-products-ve.png b/static/attachments/refguide/modeling/domain-model/view-entities/view-archived-data/all-products-ve.png new file mode 100644 index 00000000000..650d73efd61 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/view-archived-data/all-products-ve.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/view-archived-data/data-grid.png b/static/attachments/refguide/modeling/domain-model/view-entities/view-archived-data/data-grid.png new file mode 100644 index 00000000000..f567349900f Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/view-archived-data/data-grid.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/view-archived-data/domain-model.png b/static/attachments/refguide/modeling/domain-model/view-entities/view-archived-data/domain-model.png new file mode 100644 index 00000000000..5e1b5cae05b Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/view-archived-data/domain-model.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/data-grid-2.png b/static/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/data-grid-2.png new file mode 100644 index 00000000000..63fa97526a7 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/data-grid-2.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/data-grid.png b/static/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/data-grid.png new file mode 100644 index 00000000000..9eeaf33ca7e Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/data-grid.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/domain-model.png b/static/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/domain-model.png new file mode 100644 index 00000000000..85b89a134fa Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/domain-model.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/entity-properties-2.png b/static/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/entity-properties-2.png new file mode 100644 index 00000000000..76a53b7d3a1 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/entity-properties-2.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/entity-properties.png b/static/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/entity-properties.png new file mode 100644 index 00000000000..37d0840e419 Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/entity-properties.png differ diff --git a/static/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/order-info-entity.png b/static/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/order-info-entity.png new file mode 100644 index 00000000000..5d449120fdc Binary files /dev/null and b/static/attachments/refguide/modeling/domain-model/view-entities/view-entity-data-versioning/order-info-entity.png differ