Skip to content
Simon Mourier edited this page Feb 19, 2020 · 1 revision

SoftFluent CodeModeler is a model driven software factory: from a model and based on producers / generators logic, CodeModeler will produce optimized code for each targeted platform.

Architects specify the targeted platforms by declaring producers, each producer aiming one technology / platform. To do so, CodeModeler first mounts the declared model in memory thanks to its Meta Model Engine. From the mounted meta model, producers will translate the meta model into their platform specific equivalent, and in addition they will produce the required code to work with the other targeted platform.

Defining views on entities allows architects and developers to add or filter available properties of an entity:

Views

Views in CodeModeler englobe two distinct concepts: a global modeling concept, and the persistence layer concept. As explained in the introduction, when one declares a view in its model, the CodeModeler Meta Model Engine will include it in its meta model as a virtual view which will then be interpreted or not by producers. For instance, from this virtual view, the Microsoft SQL Server Producer will produce an actual SQL view, whereas the Business Object Model Producer won't produce anything specific from it. Furthermore, in producers with graphic user interfaces, views could be interpreted as a graphic representation of an entity.

Views are attached to the entity concept: an entity can have multiple views.

This section will detail the global modeling concept as well as the persistence layer concept. You can have a look at the View Editor chapter for more information on how to create views using Visual Studio.

The following example demonstrates how to declare a custom simple view with the view properties FirstName, LastName, City and Country for an Employee entity related to an Address entity:

Views - Picture 262

As we can see, we can use EPath (Entity Path) expressions in the expression attribute (“Address.City” or “Address.Country”) to navigate through entities and use their properties. The platform producer will interpret the EPath expression into the actual platform specific expression. In our case, the SQL Server Producer deduces from the EPath expression that it must add the Address_Country and Address_City columns from the Address table, as well as the corresponding LEFT OUTER JOIN.

This is the SQL Server view output (in addition to default vEmployee and vAddress views, the SQL Server producer has generated a vEmployeeCustom View.):

CREATE VIEW [Commerce].[vAddress]
AS
SELECT [Commerce].[Address].[Address_Id], [Commerce].[Address].[Address_Line1], [Commerce].[Address].[Address_Line2], [Commerce].[Address].[Address_Zip], [Commerce].[Address].[Address_City], [Commerce].[Address].[Address_Country], [Commerce].[Address].[_rowVersion], [Commerce].[Address].[_trackCreationTime], [Commerce].[Address].[_trackLastWriteTime], [Commerce].[Address].[_trackCreationUser], [Commerce].[Address].[_trackLastWriteUser] 
    FROM [Commerce].[Address]
(...)
CREATE VIEW [Commerce].[vEmployee]
AS
SELECT [Commerce].[Employee].[Employee_Id], [Commerce].[Employee].[Employee_FirstName], [Commerce].[Employee].[Employee_LastName], [Commerce].[Employee].[Employee_BirthDate], [Commerce].[Employee].[Employee_Address_Id], [Commerce].[Employee].[_rowVersion], [Commerce].[Employee].[_trackCreationTime], [Commerce].[Employee].[_trackLastWriteTime], [Commerce].[Employee].[_trackCreationUser], [Commerce].[Employee].[_trackLastWriteUser] 
    FROM [Commerce].[Employee]
(...)
CREATE VIEW [Commerce].[vEmployeeCustom]
AS
SELECT [Commerce].[Employee].[Employee_FirstName], [Commerce].[Employee].[Employee_LastName], [Commerce].[Address].[Address_City] AS 'City', [Commerce].[Address].[Address_Country] AS 'Country', [Commerce].[Employee].[_rowVersion], [Commerce].[Employee].[_trackCreationTime], [Commerce].[Employee].[_trackLastWriteTime], [Commerce].[Employee].[_trackCreationUser], [Commerce].[Employee].[_trackLastWriteUser] 
    FROM [Commerce].[Employee]
        LEFT OUTER JOIN [Commerce].[Address] ON ([Commerce].[Employee].[Employee_Address_Id] = [Commerce].[Address].[Address_Id])

Custom View Body

It's possible to implement custom views by specifying the body of the view with a CMQL method, including raw methods.

In the following example we have defined a Custom view on a Supplier entity using a raw method (the WHERE part is fully modified):

Custom View Body - Picture 263

Note: Surrounding the entity name by $ indicates to CodeModeler to use the Target Name Transformation (TNT) feature to replace the object by its persistent name. This way, one can use in raw methods actual persistent objects without being format dependent.

In this other example, we define a SupplierLightFiltered view on a Supplier entity that only redefines the WHERE part of the view using CMQL:

Custom View Body - Picture 265

Note a persistent view (resulting from a model view) will be created only if it defines at least one column after inference. For raw methods, it means you need to define at least one property on the view, otherwise the associated persistent view will not be generated. It's therefore good practice in this case to define properties that match what is returned by the custom raw code.

Derivation

Entities can derive from one another, and entities can have views. If a base entity has a view, views of its derived entities will derive from the base views.

Views as Source

You can your views in CMQL methods as source instead of the implicit entity. Using the method editor, you can just type the FROM keyword after LOAD and the auto-completion should propose you the defined views on the entity:

Views as Source - Picture 266

Furthermore, you can also use them in raw methods as well:

Views as Source - Picture 267

Note: The syntax used here uses the Target Name Transformation (TNT) feature to replace the object by its persistent name. This way, one can use in raw methods actual persistent objects without being format dependent.

Auto Lightweight Entities

As explained in the Lightweight Entities chapter, lightweight entities can be used as return types of methods.

An entity can have views, and views can be used in methods, ergo the next step would be to be able to map a lightweight entity to a view in order to have an actual object representation of it in the Business Object Model (BOM). CodeModeler allows developers to do so thanks to the “Auto infer lightweight entity” checkbox available on the View Editor.

The following example demonstrates the result of inferring a lightweight entity. We declare 3 entities: Article, Line and Command.

Auto Lightweight Entities - Picture 268

On Article, we create an ArticleByCommand view which links to Line and Command entities. The resulting view should have 3 properties: Name, ArticleQty and CommandName.

On Article, we also create a LoadArticlesByCommand CMQL method with one commandName argument that uses the ArticleByCommand view:

Auto Lightweight Entities - Picture 269

After building, this is the SQL Producer output for the ArticleByCommand view (which does the required joins) and LoadArticlesByCommand stored procedure (which reads from the view):

CREATE VIEW [Commerce].[vArticleByCommand]
AS
SELECT [Commerce].[Article].[Article_Name] AS 'ArticleName', [Commerce].[Line].[Line_Quantity] AS 'ArticleQty', [Commerce].[Command].[Command_Name] AS 'CommandName', [Commerce].[Article].[_rowVersion], [Commerce].[Article].[_trackCreationTime], [Commerce].[Article].[_trackLastWriteTime], [Commerce].[Article].[_trackCreationUser], [Commerce].[Article].[_trackLastWriteUser] 
    FROM [Commerce].[Article]
        LEFT OUTER JOIN [Commerce].[Line] ON ([Commerce].[Article].[Article_Id] = [Commerce].[Line].[Line_Article_Id])
                INNER JOIN [Commerce].[Article] [Article$1] ON ([Commerce].[Line].[Line_Article_Id] = [Article$1].[Article_Id])
                        INNER JOIN [Commerce].[Command] ON ([Commerce].[Line].[Line_Command_Id] = [Commerce].[Command].[Command_Id])
(...)
CREATE PROCEDURE [Commerce].[Article_LoadArticlesByCommand]
(
 @commandName [nvarchar] (256),
 @_orderBy0 [nvarchar] (64) = NULL,
 @_orderByDirection0 [bit] = 0
)
AS
SET NOCOUNT ON
SELECT DISTINCT [Commerce].[vArticleByCommand].[ArticleName], [Commerce].[vArticleByCommand].[ArticleQty], [Commerce].[vArticleByCommand].[CommandName], [Commerce].[vArticleByCommand].[_rowVersion], [Commerce].[vArticleByCommand].[_trackCreationTime], [Commerce].[vArticleByCommand].[_trackLastWriteTime], [Commerce].[vArticleByCommand].[_trackCreationUser], [Commerce].[vArticleByCommand].[_trackLastWriteUser] 
    FROM [Commerce].[vArticleByCommand] 
    WHERE ([Commerce].[vArticleByCommand].[CommandName] = @commandName)

And this is the BOM output, an ArticleByCommand lightweight entity class with 3 fields (ArticleName, ArticleQty and CommandName) that are bound to the vArticleByCommand view columns in the ReadRecord method (not displayed here).

// Class ArticleByCommand (Lightweight entity)
public class ArticleByCommand : ICodeModelerLightEntity
{
    // Fields
    private string _articleName;
    private int _articleQty;
    private string _commandName;
    // Methods
    public ArticleByCommand();
    void ICodeModelerLightEntity.ReadRecord(IDataReader reader);
    protected virtual void ReadRecord(IDataReader reader, ReloadOptions options);
    // Properties
    public string ArticleName { get; set; }
    public int ArticleQty { get; set; }
    public string CommandName { get; set; }
}
 
// Class ArticleByCommand: ReadRecord method
protected virtual void ReadRecord(IDataReader reader, ReloadOptions options)
{
    if (reader == null)
    {
        throw new ArgumentNullException("reader");
    }
    if ((options & 1) != 0)
    {
        this._articleName = CodeModelerPersistence.GetReaderValue(reader, "ArticleName", null);
        this._articleQty = CodeModelerPersistence.GetReaderValue(reader, "ArticleQty", 0);
        this._commandName = CodeModelerPersistence.GetReaderValue(reader, "CommandName", null);
    }
}

The BOM Producer also outputs a LoadArticlesByCommand method that returns a generic list of ArticleByCommand lightweight entities instances:

// Class ArticleCollection: LoadArticlesByCommand method
public static List<ArticleByCommand> LoadArticlesByCommand(string commandName)
{
    return PageLoadArticlesByCommand(-2147483648, 0x7fffffff, null, commandName);
}
Clone this wiki locally