Extending the Domain Model
Let's customize the model so we can update the information we need to properly track the status and location of members.
In this section, you learn how to:
- Extend an Existing Entity
- Create a Reference List
- Create a Migration Class
- Update front-end configurations to fit extended model
Let's dive right into the code!
Extending an Existing Entity
Navigate to the backend
> Shesha.Membership.sln
folder in your project directory.
Adding a Table Prefix
The concept of a table prefix
on the backend is often associated with database management systems, where it involves adding a specific string or identifier to the names of database tables. This is typically done to avoid naming conflicts and to organize tables based on certain criteria.
- Navigate to
Shesha.Membership.Domain
>Domain
>Properties
>AssemblyInfo.cs
- Modify the table prefix attribute tag to be
[assembly: TablePrefix("Mem_")]
, instead of[assembly: TablePrefix("Membership_")]
Note: While short prefixes offer these advantages, it's also crucial to strike a balance. The prefix should be long enough to be meaningful and avoid potential conflicts, but not so long that it becomes burdensome. A well-chosen, concise prefix enhances the overall quality and maintainability of the codebase.
Create a Reference List
- Create a folder called Enums in Module > Shesha.Membership.Domain.
- Right click on the Enums folder, Add > Class.
- Give your class the name of: RefListMembershipStatuses.cs, and click on Add.
- Add the below code:
using Shesha.Domain.Attributes;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Shesha.Membership.Domain.Enums
{
/// <summary>
/// Statuses for a Members Membership
/// </summary>
[ReferenceList("Mem", "MembershipStatuses")]
public enum RefListMembershipStatuses : long
{
/// <summary>
/// Membership status is still being processed
/// </summary>
[Description("In Progress")]
InProgress = 1,
/// <summary>
/// Membership status is active
/// </summary>
[Description("Active")]
Active = 2,
/// <summary>
/// Membership status is cancelled
/// </summary>
[Description("Cancelled")]
Cancelled = 3
}
}
Create a New Entity
- Navigate to
Shesha.Membership.Domain
>Domain
- Right click on the
Domain
folder,Add
>Class
- Give your class the name of:
Member.cs
, and click onAdd
- This is where we will be adding properties we want as an addition to the Person table.
This is how your class should be constructed:
using Shesha.Domain.Attributes;
using Shesha.Domain;
using System;
using Shesha.Membership.Domain.Domain.Enums;
namespace Shesha.Membership.Domain.Domain
{
/// <summary>
/// A person within the application that is a Member
/// </summary>
[Entity(TypeShortAlias = "Mem.Member")]
public class Member : Person
{
/// <summary>
/// The membership number for the Member
/// </summary>
public virtual string MembershipNumber { get; set; }
/// <summary>
/// The date when the Members membership started
/// </summary>
public virtual DateTime? MembershipStartDate { get; set; }
/// <summary>
/// The date when the Members membership ended
/// </summary>
public virtual DateTime? MembershipEndDate { get; set; }
/// <summary>
/// Identification document for the Member
/// </summary>
public virtual StoredFile IdDocument { get; set; }
/// <summary>
/// The status of the membership
/// </summary>
[ReferenceList("Mem", "MembershipStatuses")]
public virtual RefListMembershipStatuses? MembershipStatus { get; set; }
}
}
Create a Migration Class
- Navigate to
Shesha.Membership.Domain
>Migrations
- Right click on the
Migrations
folder,Add
>Class
- Create a new migration class with a file name following this format: M[YEAR][MONTH][DAY][HOUR][MINUTE][SECONDS].cs e.g. M20231124085300.cs for 24 November 2023 08:53:00.
- Add the below code:
using FluentMigrator;
using Shesha.FluentMigrator;
using System;
namespace Shesha.Membership.Domain.Migrations
{
// <summary>
/// Adding the Members table
/// </summary>
[Migration(20231124085300)]
public class M20231124085300 : Migration
{
/// <summary>
/// Code to execute when executing the migrations
/// </summary>
public override void Up()
{
Alter.Table("Core_Persons")
.AddColumn("Mem_MembershipNumber").AsString().Nullable()
.AddForeignKeyColumn("Mem_IdDocumentId", "Frwk_StoredFiles").Nullable()
.AddColumn("Mem_MembershipStartDate").AsDateTime().Nullable()
.AddColumn("Mem_MembershipEndDate").AsDateTime().Nullable()
.AddColumn("Mem_MembershipStatusLkp").AsInt64().Nullable();
}
/// <summary>
/// Code to execute when rolling back the migration
/// </summary>
public override void Down()
{
throw new NotImplementedException();
}
}
}
You can check out Fluent Migrator for more options about database migrations.
- You can run your application by going to the menu and selecting
Debug
>Start Debugging
or by clickingF5
- The application should open in your browser on the default Swagger API page.
- Search and navigate to the
Member
endpoints that have been dynamically created by Shesha.
Read more about dynamic APIs here
Updating Configurations
Now that we have fully extended our domain model, it is time to go back and update our views so that we can reference our newly created fields in the Member
entity.
This can be done by updating the Model Type property in all our views from Shesha.Domain.Person (Shesha.Core.Person)
to Shesha.Membership.Domain.Member (Mem.Member)
, changing CRUD endpoints to point to the relevant model type, and adding the following fields:
- MembershipNumber -
Textfield
:string
- MembershipStatus -
RadioButton
:RefListMembershipStatuses
- MembershipStartDate -
Datefield
:DateTime
- MembershipEndDate -
Datefield
:DateTime
- IdDocument -
File
:StoredFile
Create View
- Navigate to the
member-create
form designer - Select
Settings
and change theEntity
toShesha.Membership.Domain.Member (Mem.Member)
With the addition of properties to our entity, to facilitate for an overall cleaner and more managable UI, we are going to be utilizing a wizard
component for properly delinating the different sections of information required for the member registration.
You can find more information about implementation of the wizard component here
- Search and drag in a
wizard
component from theBuilder Widgets
- Drag in all the existing components onto the
wizard
component's draggable area
Configure Wizard Steps
to rename the defaultStep 1
and add an additional step to the wizard:- Biographical Information
- Membership Information
-
Update the
Membership Information
step'sDone
button to the following:- After Done Action:
Execute Script
>
- After Done Action:
(function () {
const PATH = `/api/dynamic/Shesha.Membership/Member/Create`;
http.post(`${PATH}`, data).then(onSuccess).catch(onError);
})();
function onSuccess(resp) {
// Navigate to details view of the created member
window.location.href = `/dynamic/Shesha.Membership/member-details?id=${resp.data.result.id}`;
}
function onError(_e) {
message.error(`Failed to create member: ${_e}`, 10);
}
- While on the
Biographical Information
step of the wizard, search and drag in theFile
component from theBuilder Widgets
.
You can find more information about implementation of the file component here
-
Configure the
File
component with the following:- Property Name :
idDocument
- Label :
Id Document
- Owner Id: leave empty
- Property Name :
-
While on the
Biographical Information
step of the wizard, search and drag in theEntity Picker
component from theBuilder Widgets
.
You can find more information about implementation of the entity picker component here
- Configure the
Entity Picker
component with the following:
- Property Name :
address
- Label :
Address
- Entity Type:
Shesha.Domain.Address (Shesha.Core.Address)
Configure Columns
of the wizard to include the following columns:
- addressLine1
- suburb
- town
One of the Entity Picker
components many benefits is that it provides the flexibility to allow the addition of a new record, should the address
entry not exist in any of the existing records brought back from the backend. To tap into the full functionality, we need to go create a form that will allow us to enter the details of the new address entry.
In another tab, go create a new form with the following information:
- Module:
Shesha
- Template:
form-view
- Name:
address-create
- Label:
Address Create
- Description:
This create view is used to create a new address
- Model Type:
Shesha.Domain.Address (Shesha.Core.Address)
Once on the form designer, on the Data Panel
, drag and drop properties onto the Edit Area
and autocomplete or change the labels accordingly:
- addressLine1
- suburb
- town
Save your form and head back to the member-create
form designer
- Select the
Entity Picker
component >Allow New Record
- Populate the
Dialogue Settings
with the following:
- Title:
Add Address
- Modal Form:
address-create
- Show Modal Buttons:
true
-
Click on the
next
button on theWizard
component to go to the next step. -
On the
Data Panel
, drag and drop properties onto theEdit Area
and autocomplete or change the labels accordingly:- membershipNumber
- membershipStartDate
- membershipEndDate
- membershipStatus
-
Add additional validations on the
membershipStartDate
andmembershipEndDate
properties by selecting the respectiveDateField
components and configure the following:- Disabled Date Mode:
Function Template
- Disabled Date Template:
Disable Past Dates
- Disabled Date Mode:
- Save your form
Table View
- Navigate to the
members-table
form designer - Select
Settings
and change theEntity
toShesha.Membership.Domain.Member (Mem.Member)
- Select the
Datatable Context
component and change theEntity Type
toShesha.Membership.Domain.Member (Mem.Member)
- Select the
Datatable
component >Customize Columns
to add the relevant columns
- Select the
Button Group
component on thetoolbar
to customize theCreate Member
button - Update the
Create Member
button configurations by seeting theButton Type
property toNone
.
This is because we will be using the default wizard
buttons that were configured on the member-create
.
- Save your form
Details View
- Navigate to the
member-details
form designer - Select
Settings
and change theEntity
toShesha.Membership.Domain.Member (Mem.Member)
With the addition of properties to our entity, to facilitate for an overall cleaner and more managable UI, we are going to be utilizing a tab
component for properly delinating the different sections of the membership information.
You can find more information about implementation of the tab component here
- Search and drag in a
tab
component from theBuilder Widgets
onto thedetails
panel - Drag in all the existing components onto the
tab
component's draggable area
Configure Tab Panes
to rename the defaultTab 1
and add an additional tab.
- While on the
Biographical Information
tab, search and drag in theFile
component from theBuilder Widgets
.
You can find more information about implementation of the file component here
-
Configure the
File
component with the following:- Property Name :
idDocument
- Label :
Id Document
- Owner Id:
{data.id}
- Owner Type:
Shesha.Membership.Domain.Domain.Member
- Property Name :
- Viewing the details of a foreign key on a details view can be achieved in a number of ways:
For the purposes of this tutorial, we are going to be utilizing the Entity Reference
component
- While on the
Biographical Information
tab, search and drag in theEntity Reference
component from theBuilder Widgets
.
You can find more information about implementation of the entity reference component here
-
Configure the
Entity Reference
component with the following:- Property Name :
address
- Label :
Address
- Get Entity Url :
/api/dynamic/Shesha/Address/Get
- Entity Type :
Shesha.Domain.Address (Shesha.Core.Address)
- Display Property :
fullAddress
- Entity Reference Type:
Modal Dialog Box
- Form Selection Mode:
Name
- Form:
address-create
- Dialog Settings:
- Title:
Address
- Show Modal Buttons:
true
- Submit Http Verb:
PUT
- Handle Success:
Designer Form
>Refresh
- Title:
- Property Name :
This will render the address details on a dialog and allow for editing and updating the address entry on the rendered dialog
-
Click on the
Membership Information
tab on thetab panel
to go to the next tab. -
On the
Data Panel
, drag and drop properties onto theEdit Area
and autocomplete or change the labels accordingly:- membershipNumber
- membershipStartDate
- membershipEndDate
- membershipStatus
To further personalize the membership details view, let's make some changes to our header
section.
- Select the
text
component used for the title and change thecontent
property to{{fullName}} - {{membershipNumber}}
- Search and drag in the
Reference List Status
component from theBuilder Widgets
next to thetext
title component
You can find more information about implementation of the reference list status component here
-
Configure the
Reference List Status
component with the following:- Property Name :
membershipStatus
- Reference List:
MembershipStatuses
- Property Name :
-
Save your form
Let's test out our new changes!
- Using the main menu, navigate to the
members-table
and refresh your page to make sure your changes have taken effect. - Register a new member!