Advanced programming


You can add additional tables and fields to the existing iPlus database. Since you cannot change the entity framework models from gip.core.datamodel or gip.mes.datamodel, you have to add your own model in your custom assembly. 

Of course, you can also create your own database and use iPlus. However, it doesn't matter which of the two variants you prefer, the work steps are the same in both cases:

  1. Create a new assembly.
  2. Generate an entity framework data model.
  3. Generate and and modify T4 template for database-first approach.
  4. Compiled models
  5. Extend database context class with iPlus features.
  6. Deploy updates using SQL scripts.
  7. Add partial entity classes.
  8. Model updates

Note: When switching from EF4 to EFCore, the script dbsync_2023-05-15_00-01_iplusV5.sql and dbsync_2023-03-31_00-01_reportHandlerV5.sql must be run first.

 

You can download this sample project in the download area


Use Visual Studio to add a new assembly project (.NET 7). 

Please note the iPlus naming conventions when naming your assembly, otherwise it will not be recognized during the registration process. (The registration process is carried out during login by holding down the Ctrl key and pressing the login button). We recommend ending the file name with "*.datamodel.dll" .

In the sample project we have named it mycompany.package.datamodel.dll.


Before reading further, please familiarize yourself with creating Entity Framework data models.

You can create the model using the database-first approach and using the code-first approach. The  "database-first approach" and "reverse engineering"  is supported by iPlus. You can also use the code-first approach, but you will have to do the migrations yourself. The migration or automatic update of the database tables is provided in iPlus using SQL scripts, which is described in more detail later in section "E. Providing updates using SQL scripts". 

The ACObjectContextHelper class was briefly discussed in the previous chapter. It is an auxiliary class for extending the "Microsoft.EntityFrameworkCore.DbContext" class to include iPlus features (such as length checks, min / max values, automatic setting of time stamps, default values, extended reference checks when deleting ...). 

If you use the database-first approach, you will need the Microsoft.EntityFrameworkCore.Design and Microsoft.EntityFrameworkCore.Tools packages. It is important that you comment out the IncludeAssets section in the project configuration, which Visual Studio adds automatically. And you must set the PrivateAssests segment to compile:


Before using the commands to install the T4 templates you need to have the dotnet tools installed, you can install them using this command in the .NET CLI:

dotnet tool install --global dotnet-ef

This command always installs the latest version of EF-Tools:

https://learn.microsoft.com/de-de/ef/core/get-started/overview/install

However, you should always only use the version that matches the current .NET Core Framework version or EF Core version:

dotnet tool update dotnet-ef --version 8.0.11 --global

Uninstall-Command:

dotnet tool uninstall dotnet-ef --global

 
When using the database-first approach you need to install the T4 template package and add the templates to the project. You can install the package using this command in the .NET CLI: 

dotnet new install Microsoft.EntityFrameworkCore.Templates

and after that running this command will create the T4 templates:

dotnet new ef-templates

The T4 templates are created in the solution directory:

  • CodeTemplates/
    • EFCore/
      • DbContext.t4
      • EntityType.t4

If you wish to change the directory for the created templates, you can use the command option --output <output>, which will allow you to specify a different output directory.

Once the T4 templates are generated, replace them with the iPlus T4 Templates from the sample project. These templates define how the entities are created from the database.

Feel free to modify the templates according to your specific requirements. At present, they create the Entities and Context class, making them compatible with iPlus. You can also debug them by following the official guide provided by Microsoft.

Instead of creating the teplates yourself, reuse the templates from the example project. You only have to replace the namespace and OnConfiguring Section with your namespace and the classname of your Database-class (E), that is derived from the base class, that is generated via the T4-Templates and derived from the DbContextClass (read section 6).

 

To execute the templates, utilize the Scaffold-DbContext command in the Package Manager Console. Ensure that the package Microsoft.EntityFrameworkCore.Design is installed in the project where you are scaffolding, along with the relevant database provider package.

In the sample project the command used to scaffold the entities was:

Scaffold-DbContext "Server=.\;Database=ExampleV4;Trusted_Connection=True;Encrypt=False" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -UseDatabaseName

Before running this command, you need to specify the connection string in the App.config file (H). 

<connectionStrings>    
<add name="MyCompanyDB_Entities"
connectionString=" Integrated Security=True;      
Encrypt=False;         
data source=.\SQLEXP16;                                                    
initial catalog=ExampleV5;    
Trusted_Connection=False;         
persist security info=True;                                                    
user id=gip;                                                    
password=mypw;                                                    
multipleactiveresultsets=True;                                                    
application name=EntityFramework'"/> 
</connectionStrings>

Also we recommend, to activate a Pluralizer before running the scaffolding. Read the next section first please:


For the T4 generator to work, you should follow these naming rules:

  1. Use primary key of the type (GUID / uniqueidentifier) (1) .
  2. Name the primary key like the table name and add "ID" at the end. e.g.  "InOrderPosID" (2).
  3. Foreign keys should be named so that they end with the name of the primary key of the referenced table (3).
  4. You can optionally use cascaded deletion (e.g. header and position tables) (4).

     

  5. The Entity Framework scaffolder has the undesirable property of shortening table names. To prevent this from happening, you need a pluralizer class that is automatically included. Simply use the two classes (MyDesignTimeServices, MyPluralizer) from the example project and insert them into your project exactly as they are.
  6. In cases where the entity name ends in a plural, it's essential to be mindful that the T4 Template pluralizer may alter the table name accordingly. Consequently, you should modify it as necessary to ensure it aligns with your preferences and needs.

To add the iPlus features, create a new C# file with a new class that inherits from the class that generated the T4 template. In our example, the MyCompanyDB class that inherits from ExampleV5Context:

 

Provide MyCompanyEntites with the ACClassInfo attribute class of type "Global.ACKinds .TACDBAManager". With this setting, you announce your new database context class to the iPlus framework so that it appears in the iPlus development environment in the iPlus application tree (after you have started iPlus with the Ctrl key). 

(If you  create your database model using the model-first approach, you must also provide your context class with the ACClassInfo attribute class as described above.)

MyCompanyEntites must also implement the gip.core.datamodel.IACEntityObjectContext interface. To do this, instantiate the auxiliary class ACObjectContextHelper. The methods and properties of this class are named exactly the same as those in the IACEntityObjectContext interface. So all you have to do is delegate the method calls in your class to the ACObjectContextHelper instance and you have expanded your context with iPlus features.

(The use of the iPlus features (ACObjectContextHelper) is not possible with the model-first approach and therefore you have to implement the interface yourself)


After executing the T4 template the main context class is named after the database name + context. In the sample code provided the context class is named ExampleV5Context and the class was declared as follows:

public partial class ExampleV5Context : DbContext

Compiled Models

iPlus uses compiled models for the perfomance benefits(up to 10x better performance and decereased startup time). To use compiled models you need to run the command in the .NET CLI.

Before running the command, it is necessary to make adjustments to the code within the context class, which is generated by the T4 Templates. In the OnConfiguring() method of this class, ensure that the method .UseSqlServer() is uncommented and the method UseModel() is commented, and subsequently, modify the connection string. This step is crucial because Entity Framework relies on the context class to determine the database connection used for creating the compiled models, and the model isn't yet created.

The following command serves as a reference from the sample project. However, in your individual project, you must tailor the parameters for the project, context, and namespace options to align with your specific requirements:

NET CLI: dotnet ef dbcontext optimize --output-dir CompiledModels --namespace mycompany.package.datamodel --project mycompany.package.datamodel --context ExampleV5Context

Upon successful execution of the command, it is necessary to comment out the connection string and uncomment the method responsible for utilizing compiled models.

 


Model Updates

Whenever the model is changed or updated, it is necessary to run the scaffold command and then the optimize command. However, this time, you need to use the --force parameter with the scaffold command to overwrite the existing classes. This process is automated with a the Power-Shell-Script iPlusModelUpdate.ps1. The script is located in the CodeTemplates folder. You have to modify the parameters at the beginning of the script first.

$databaseConnectionString = "data source=.\SQLEXP16;Initial catalog=ExampleV5;Trusted_Connection=False;Encrypt=False;user id=gip;password=netspirit;"
$namespace = "mycompany.package.datamodel"
$outputDir = "EFModels"
$compiledOutputDir = "EFCompiledModels"
$efBaseName = "MyCompanyDB";

Note:

If you have an exception or an error in your code the scaffold process won't execute, you have the option to utilize the --no--build parameter in the scaffold command. This parameter serves the purpose of preventing the project from being built automatically during the scaffolding operation.


If you have made changes in tables, fields and relations and have updated your edmx model, your software will not yet work for other customers because the installation there must also be updated to the latest database.

The iPlus update system does this for you. Before the actual assembly registration process, which you start with the Ctrl key when you log in to iPlus, SQL scripts can be executed automatically. This update logic is implemented in the assembly "gip.core.dbsyncer.dll". The following settings must be made for this to work:

 

  1. Create a folder with the name "DbScripts".
  2. Create a subfolder that is named with a name of up to 10 characters. "MyCompDB" in the example above.
  3. Create an info.xml file in this folder with the following content:

 

 

4. Enter the name of the folder in the <DbSyncerInfoContextID> element in which this xml file is located.

5. Enter the name of the entity container in the <ConnectionName> element, which also corresponds to the class name that the T4 generator has created.

6. You can enter any description text in the <Name> element.

7. The info-xml must always be copied into the bin directory during the build. Therefore, set the property "Copy to output directory" to "Always copy" or "Copy if newer".

 

From this moment on, your project can now be updated. Any future database changes you make on your development system must be added as an SQL script in your project folder. Also set it like "info.xml" to "Always copy" so that the SQL script is copied into the build directory for later deployment. If there are different edmx models that work with the same database, the scripts must be synchronized with one another across all contexts. So that the DB-Syncer (gip.core.dbsyncer.dll) does this in the correct order, the SQL script file names must be assigned according to a defined naming scheme, which contain an exact time stamp :

dbsync_YYYY-MM-DD_hh-mm_developername.sql

The developername can be replaced by the actual developer, department or company name. This then appears in the SQL change history that is stored in the table [@DbSyncerInfo]:

 

The column names in the table [@DbSyncerInfoContext] correspond to the element names in the info.xml file. (The Order field is irrelevant, you can use any number).

 

Important: ConnectionStrings.config = SQL scripts!

The ConnectionString.config must have a separate <add> section for each database or for each entity container name. For "gip.core.datamaodel.Database" the entity container name is "iPlusV4_Entities". For "gip.mes.datamodel.DatabaseApp" it is "iPlusMESV4_Entities".

SQL update scripts are executed on the database that is set in the corresponding connection string. This allows you to control whether you want to manage or update a database separate from iPlus or whether you want to add your custom tables to the iPlus database! In both cases, however, the change history is written to the iPlus database!

 


The Entity Framework Generator generates the following framework signature based on the T4 template:

public partial class Material : VBEntityObject, IInsertInfo, IUpdateInfo, IDeleteInfo

gip.core.datamodel.VBEntityObject is the base class for all entity classes so that the additional iPlus features can be used. It specifies a number of virtual methods and common functionalities that can be overwritten or reused in the derivations. The interfaces IInsertInfo, IUpdateInfo and IDeleteInfo are added automatically because the T4 template examines the entities according to the fields "InsertDate, InsertName, UpdateName ...".

Then program the rest of the program code in another C# file where you extend the partial class (see F in the first picture above). The partial class should be expanded with the following color-coded code areas:

 

Partial class definition (A)

Add a partial class definition.

 

Classes and property description using attribute classes 

(A) & (B):  Add an  ACClassInfo attribute class  (A) with Global.ACKinds .TACDBA  (B). This is how you announce this entity class to the iPlus framework. It then appears in the development environment below the associated database context class in the iPlus application tree (this also applies to the  model-first approach).

(C): Since the properties of the entity class are declared in the other partial class created by the T4 template generator, the ACClassPropertyInfo attribute cannot be declared there, because it will be removed by running again the T4 template. Instead, use the ACPropertyEntity attribute class (C). For each database field or property of the entity class, you declare an ACPropertyEntity line and enter the name of the property in the first parameter. The remaining construction parameters are the same as for the  ACClassPropertyInfo class. For string properties (SQL type varchar), enter the maximum length of the string with "MaxLength".

However, if you use the model-first approach (by foregoing the iPlus features), you can use the ACClassPropertyInfo attribute as normal for your properties.

(D):  Optional: Define a template for the storable queries (ACQueryDefinition). A storable query should always be defined if the table (or the entity class) in business objects is the main table which is filtered and navigated to.

(F): Optional: Define an ACSerializable attribute so that a smart pointer to an object of this entity class can be used in a network capable property.

 

Implementation of VBEntityObject

VBEntityObject has several virtual methods with a standard implementation for adding, deleting and changing objects. Because of Entity Framework Core and short lived contexts it is important for every Entity object to inherit VBEntityObject as it has the property of the long lived context and other important properties that are crucial for compatibility as EntityKey. Overwrite this if you want to add your individual logic and call the basic implementation at the end of the method.

(A): To add new objects, declare a static method with the following signature:

public static MyEntityClassT NewACObject(MyDbContextClass dbApp, IACObject parentACObject, string secondaryKey)

In this method, you then create a new instance of the entity class (MyEntityClassT) and set the primary key with a new GUID (B) .

(C): Then call the extension method DefaultValuesACObject() so that all properties of your entity class or generally of an IACObject are initialized with the default values ​​that have been configured in the development environment.

(D): If your table has a secondary key (a database field with a legible key), you can use the number generator to generate it and pass it to the "secondaryKey" parameter. The number ranges of the number generator can be configured with the business object gip.bso.iplus.BSONoConfiguration in advance.

(E): Call the SetInsertAndUpdateInfo() method to have the user name and the current time entered in the "Insert" fields.

Attention: The object is not yet in change tracking! Either add the newly generated object immediately to the DB context or do it outside of the NewACObject() method.

Important V5 Changes: When adding properties to the partial Entity Class it is important to add the [NotMapped] attribute as Entity Framework Core will map the properties to the database because of it's default behavior.