415 Fifth entity of ABP framework applications - chempkovsky/CS82ANGULAR GitHub Wiki
- Our fifth entity will be PhbkDivision. We just follow the same steps as for 070 Fifth View (Phone)
- In the
Phbk
folder of therupbes.firstapp.Domain.csproj
project, create a class as shown below. We inherit the class from Entity
Click to show the code
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Volo.Abp;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;
using Volo.Abp.MultiTenancy;
namespace rupbes.firstapp.Phbk
{
public class PhbkPhone : Entity<int>, IMultiTenant, IHasConcurrencyStamp
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Display(Description = "Row id", Name = "Phone Id", Prompt = "Enter Phone Id", ShortName = "Phone Id")]
[Required]
public override int Id { get; protected set; }
[StringLength(20, MinimumLength = 3, ErrorMessage = "Invalid")]
[Display(Description = "Name of the Phone Type", Name = "Phone", Prompt = "Enter Phone", ShortName = "Phone")]
[Required]
public string Phone { get; protected set; } = null!;
[Display(Description = "Row id", Name = "Phone Type Id", Prompt = "Enter Phone Type Id", ShortName = "Phone Type Id")]
[Required]
public int PhoneTypeIdRef { get; protected set; }
[Display(Description = "Row id", Name = "Id of the Employee", Prompt = "Enter Employee Id", ShortName = "Employee Id")]
[Required]
public int EmployeeIdRef { get; protected set; }
[DisableAuditing]
[Display(Description = "Concurrency Stamp", Name = "Concurrency Stamp", Prompt = "Enter Concurrency Stamp", ShortName = "Concurrency Stamp")]
[StringLength(40, MinimumLength = 0, ErrorMessage = "Invalid")]
[Required]
[ConcurrencyCheck]
public virtual string ConcurrencyStamp { get; set; } = default!;
[Display(Description = "Tenant id", Name = "Tenant Id", Prompt = "Enter Tenant Id", ShortName = "Tenant Id")]
public virtual Guid? TenantId { get; protected set; }
#if (!NOTMODELING)
public PhbkPhoneType PhoneType { get; set; } = null!;
public PhbkEmployee Employee { get; set; } = null!;
#endif
public PhbkPhone() : base()
{
ConcurrencyStamp = Guid.NewGuid().ToString("N");
}
public PhbkPhone(int id, string phone, int phoneTypeIdRef, int employeeIdRef) : base(id)
{
Check.NotNullOrWhiteSpace(phone, nameof(Phone));
Phone = phone;
PhoneTypeIdRef = phoneTypeIdRef;
EmployeeIdRef = employeeIdRef;
ConcurrencyStamp = Guid.NewGuid().ToString("N");
}
public virtual void ChangeVals(string phone, int phoneTypeIdRef, int employeeIdRef, string concurrencyStamp)
{
Check.NotNullOrWhiteSpace(phone, nameof(Phone));
Phone = phone;
PhoneTypeIdRef = phoneTypeIdRef;
EmployeeIdRef = employeeIdRef;
ConcurrencyStamp = concurrencyStamp;
}
}
}
- We have to modify
PhbkEmployee
-class as well.
Click to show the code
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Volo.Abp;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;
using Volo.Abp.MultiTenancy;
namespace rupbes.firstapp.Phbk
{
public class PhbkEmployee : Entity<int>, IMultiTenant, IHasConcurrencyStamp
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Display(Description = "Row id", Name = "Id of the Employee", Prompt = "Enter Employee Id", ShortName = "Employee Id")]
[Required]
public override int Id { get; protected set; }
[Display(Description = "First Name of the Employee", Name = "Employee First Name", Prompt = "Enter Employee First Name", ShortName = "First Name")]
[StringLength(25, MinimumLength = 3, ErrorMessage = "Invalid")]
[Required]
public string EmpFirstName { get; protected set; } = null!;
[Display(Description = "Last Name of the Employee", Name = "Employee Last Name", Prompt = "Enter Employee Last Name", ShortName = "Last Name")]
[StringLength(40, MinimumLength = 3, ErrorMessage = "Invalid")]
[Required]
public string EmpLastName { get; protected set; } = null!;
[Display(Description = "Row id", Name = "Employee Second Name", Prompt = "Enter Employee Second Name", ShortName = "Second Name")]
[StringLength(25, ErrorMessage = "Invalid")]
public string? EmpSecondName { get; protected set; }
[Display(Description = "Row id", Name = "Id of the Division", Prompt = "Enter Division Id", ShortName = "Division Id")]
[Required]
public int DivisionIdRef { get; protected set; }
[DisableAuditing]
[Display(Description = "Concurrency Stamp", Name = "Concurrency Stamp", Prompt = "Enter Concurrency Stamp", ShortName = "Concurrency Stamp")]
[StringLength(40, MinimumLength = 0, ErrorMessage = "Invalid")]
[Required]
[ConcurrencyCheck]
public virtual string ConcurrencyStamp { get; set; } = default!;
[Display(Description = "Tenant id", Name = "Tenant Id", Prompt = "Enter Tenant Id", ShortName = "Tenant Id")]
public virtual Guid? TenantId { get; protected set; }
public PhbkEmployee() : base()
{
ConcurrencyStamp = Guid.NewGuid().ToString("N");
}
public PhbkEmployee(int id, string empFirstName, string? empLastName, string? empSecondName, int divisionIdRef ) : base(id)
{
Check.NotNullOrWhiteSpace(empFirstName, nameof(EmpFirstName));
Check.NotNullOrWhiteSpace(empLastName, nameof(EmpLastName));
EmpFirstName = empFirstName;
EmpLastName = empLastName;
EmpSecondName = empSecondName;
DivisionIdRef = divisionIdRef;
ConcurrencyStamp = Guid.NewGuid().ToString("N");
}
public virtual void ChangeVals(string empFirstName, string? empLastName, string? empSecondName, int divisionIdRef, string concurrencyStamp)
{
Check.NotNullOrWhiteSpace(empFirstName, nameof(EmpFirstName));
Check.NotNullOrWhiteSpace(empLastName, nameof(EmpLastName));
EmpFirstName = empFirstName;
EmpLastName = empLastName;
EmpSecondName = empSecondName;
DivisionIdRef = divisionIdRef;
ConcurrencyStamp = concurrencyStamp;
}
#if (!NOTMODELING)
public PhbkDivision Division { get; set; } = null!;
public virtual List<PhbkPhone> Phones { get; set; } = null!;
#endif
}
}
- We have to modify
PhbkPhoneType
-class as well.
Click to show the code
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Volo.Abp;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;
using Volo.Abp.MultiTenancy;
namespace rupbes.firstapp.Phbk
{
public class PhbkPhoneType : BasicAggregateRoot<int>, IMultiTenant, IHasConcurrencyStamp
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Display(Description = "Row id", Name = "Phone Type Id", Prompt = "Enter Phone Type Id", ShortName = "Phone Type Id")]
[Required]
public override int Id { get; protected set; } = default!;
[StringLength(20, MinimumLength = 3, ErrorMessage = "Invalid")]
[Display(Description = "Name of the Phone Type", Name = "Phone Type Name", Prompt = "Enter Phone Type Name", ShortName = "Phone Type Name")]
[Required]
public string PhoneTypeName { get; protected set; } = default!;
[Display(Description = "Description of the Phone Type", Name = "Phone Type Description", Prompt = "Enter Phone Type Description", ShortName = "Phone Type Description")]
[StringLength(250, ErrorMessage = "Invalid")]
public string? PhoneTypeDesc { get; protected set; }
[DisableAuditing]
[Display(Description = "Concurrency Stamp", Name = "Concurrency Stamp", Prompt = "Enter Concurrency Stamp", ShortName = "Concurrency Stamp")]
[StringLength(40, MinimumLength = 0, ErrorMessage = "Invalid")]
[Required]
[ConcurrencyCheck]
public virtual string ConcurrencyStamp { get; set; } = default!;
[Display(Description = "Tenant id", Name = "Tenant Id", Prompt = "Enter Tenant Id", ShortName = "Tenant Id")]
public virtual Guid? TenantId { get; protected set; }
public PhbkPhoneType() : base()
{
ConcurrencyStamp = Guid.NewGuid().ToString("N");
}
public PhbkPhoneType(int id, string phoneTypeName, string? phoneTypeDesc) : base(id)
{
Check.NotNullOrWhiteSpace(phoneTypeName, nameof(PhoneTypeName));
PhoneTypeName = phoneTypeName;
PhoneTypeDesc = phoneTypeDesc;
ConcurrencyStamp = Guid.NewGuid().ToString("N");
}
public virtual void ChangeVals(string phoneTypeName, string? phoneTypeDesc, string concurrencyStamp)
{
Check.NotNullOrWhiteSpace(phoneTypeName, nameof(PhoneTypeName));
PhoneTypeName = phoneTypeName;
PhoneTypeDesc = phoneTypeDesc;
ConcurrencyStamp = concurrencyStamp;
}
#if (!NOTMODELING)
public virtual List<PhbkPhone> Phones { get; set; } = null!;
#endif
}
}
- Repeat the steps of the 403 Modify DBContext for the first entity (PhoneType).
OnModelCreating
must be as follows:
Click to show the code
protected override void OnModelCreating(ModelBuilder builder)
{
#if (!NOTMODELING)
builder.Entity<PhbkFile>().HasKey(p => new { p.FileId, p.FlNm });
builder.Entity<PhbkPhone>().HasKey(p => p.Id);
builder.Entity<PhbkEmployee>().HasKey(p => p.Id);
builder.Entity<PhbkDivision>().HasKey(p => p.Id);
builder.Entity<PhbkPhoneType>().HasKey(p => p.Id);
builder.Entity<PhbkEnterprise>().HasKey(p => p.Id);
#endif
base.OnModelCreating(builder);
/* Include modules to your migration db context */
builder.ConfigurePermissionManagement();
builder.ConfigureSettingManagement();
builder.ConfigureBackgroundJobs();
builder.ConfigureAuditLogging();
builder.ConfigureFeatureManagement();
builder.ConfigureIdentity();
builder.ConfigureOpenIddict();
builder.ConfigureTenantManagement();
builder.ConfigureBlobStoring();
/* Configure your own tables/entities inside here */
//builder.Entity<YourEntity>(b =>
//{
// b.ToTable(firstappConsts.DbTablePrefix + "YourEntities", firstappConsts.DbSchema);
// b.ConfigureByConvention(); //auto configure for the base class props
// //...
//});
builder.ConfigurefirstappDbContext();
#if (!NOTMODELING)
builder.Entity<PhbkDivision>().HasOne(d => d.Enterprise)
.WithMany(m => m.Divisions)
.HasForeignKey(d => d.EntrprsIdRef)
.HasPrincipalKey(p => p.Id)
.IsRequired(true)
.OnDelete(DeleteBehavior.NoAction);
builder.Entity<PhbkEmployee>().HasOne(d => d.Division)
.WithMany(m => m.Employees)
.HasForeignKey(d => d.DivisionIdRef)
.HasPrincipalKey(p => p.Id)
.IsRequired(true)
.OnDelete(DeleteBehavior.NoAction);
builder.Entity<PhbkPhone>().HasOne(d => d.PhoneType)
.WithMany(m => m.Phones)
.HasForeignKey(d => d.PhoneTypeIdRef)
.HasPrincipalKey(p => p.Id)
.IsRequired(true)
.OnDelete(DeleteBehavior.NoAction);
builder.Entity<PhbkPhone>().HasOne(d => d.Employee)
.WithMany(m => m.Phones)
.HasForeignKey(d => d.EmployeeIdRef)
.HasPrincipalKey(p => p.Id)
.IsRequired(true)
.OnDelete(DeleteBehavior.NoAction);
#endif
}
-
ConfigurefirstappDbContext
must be as follows:
public static class firstappDbContextCreatingExtensions
{
public static void ConfigurefirstappDbContext(
this ModelBuilder builder)
{
Check.NotNull(builder, nameof(builder));
builder.Entity<PhbkPhoneType>(b =>
{
b.ToTable(firstappConsts.DbTablePrefix + "PhbkPhoneTypes", firstappConsts.DbSchema);
b.ConfigureByConvention(); //auto configure for the base class props
//...
b.HasKey(p => p.Id);
});
builder.Entity<PhbkFile>(b =>
{
b.ToTable(firstappConsts.DbTablePrefix + "PhbkFiles", firstappConsts.DbSchema);
b.ConfigureByConvention(); //auto configure for the base class props
//...
b.HasKey(p => new { p.FileId, p.FlNm });
});
builder.Entity<PhbkEnterprise>(b =>
{
b.ToTable(firstappConsts.DbTablePrefix + "PhbkEnterprises", firstappConsts.DbSchema);
b.ConfigureByConvention(); //auto configure for the base class props
//...
b.HasKey(p => p.Id);
});
builder.Entity<PhbkDivision>(b =>
{
b.ToTable(firstappConsts.DbTablePrefix + "PhbkDivisions", firstappConsts.DbSchema);
b.ConfigureByConvention(); //auto configure for the base class props
//...
b.HasKey(p => p.Id);
// builder.Entity<PhbkDivision>().HasOne(d => d.Enterprise)
b.HasOne<PhbkEnterprise>()
//.WithMany(m => m.Divisions)
.WithMany()
.HasForeignKey(d => d.EntrprsIdRef)
.HasPrincipalKey(p => p.Id)
.IsRequired(true)
.OnDelete(DeleteBehavior.NoAction);
});
builder.Entity<PhbkEmployee>(b =>
{
b.ToTable(firstappConsts.DbTablePrefix + "Employes", firstappConsts.DbSchema);
b.ConfigureByConvention(); //auto configure for the base class props
//...
b.HasKey(p => p.Id);
//builder.Entity<PhbkEmployee>().HasOne(d => d.Division)
b.HasOne<PhbkDivision>()
// .WithMany(m => m.Employees)
.WithMany()
.HasForeignKey(d => d.DivisionIdRef)
.HasPrincipalKey(p => p.Id)
.IsRequired(true)
.OnDelete(DeleteBehavior.NoAction);
});
builder.Entity<PhbkPhone>(b =>
{
b.ToTable(firstappConsts.DbTablePrefix + "Phones", firstappConsts.DbSchema);
b.ConfigureByConvention(); //auto configure for the base class props
//...
b.HasKey(p => p.Id);
// builder.Entity<PhbkPhone>().HasOne(d => d.PhoneType)
b.HasOne<PhbkPhoneType>()
//.WithMany(m => m.Phones)
.WithMany()
.HasForeignKey(d => d.PhoneTypeIdRef)
.HasPrincipalKey(p => p.Id)
.IsRequired(true)
.OnDelete(DeleteBehavior.NoAction);
//builder.Entity<PhbkPhone>().HasOne(d => d.Employee)
b.HasOne<PhbkEmployee>()
// .WithMany(m => m.Phones)
.WithMany()
.HasForeignKey(d => d.EmployeeIdRef)
.HasPrincipalKey(p => p.Id)
.IsRequired(true)
.OnDelete(DeleteBehavior.NoAction);
});
}
}
Please take a look at b.HasOne<PhbkPhoneType>()
-operator (and b.HasOne<PhbkEmployee>()
-operator). We declare foreign key without using .WithMany(m => m.Phones)
and .HasOne(d => d.PhoneType)
operators since Employee
-property and Phones
-property declared to be used only at modeling time
#if (!NOTMODELING)
public PhbkPhoneType PhoneType { get; set; } = null!;
public PhbkEmployee Employee { get; set; } = null!;
#endif
...
#if (!NOTMODELING)
public virtual List<PhbkPhone> Phones { get; set; } = null!;
#endif
...
#if (!NOTMODELING)
public PhbkDivision Division { get; set; } = null!;
public virtual List<PhbkPhone> Phones { get; set; } = null!;
#endif
- First foreign key will be as follows:
Click to show the picture
- Second foreign key will be as follows:
Click to show the picture
- Repeat the steps of the 404 First View (PhoneType). Wizard repository
Click to show the picture
- This is how the first prefix is defined:
Click to show the picture
- This is how the second prefix is defined:
Click to show the picture
- Repeat the steps of the 405 First Web Api Service (PhoneType)
- Please note that
Use only root props for select method
-checkbox is ON. It meansDEEntrprsName
-prop andDivisionName
-prop will not be generated for DTO-class. This is because we are using the Apb-repo class.
Click to show the picture
-
Repeat the steps of the 408 Typescript Classes for the First View of ABP framework.
-
Repeat the steps of the 409 Navigation aware typescript components for the First View of ABP framework.
-
UI List properties is as follows:
Click to show the picture
- UI Form properties is as follows:
Click to show the picture
-
EDEEntrprsName
-prop andEDDivisionName
-prop andPPhoneTypeName
-prop haveSearchDialog
-input type even forDelete and View
-forms. If we assignreadonly or default
-type forEDEEntrprsName
-prop andEDDivisionName
-prop andPPhoneTypeName
-prop than they will not be displayed onDelete and View
-forms. -
Modify
app-routing.module.ts
-file forPhbkEmployee
-entity as before. -
For
PhbkPhoneType
-entity (direct master):- Regenerate
routing
-code again, as the routing items number has changed - Regenerate typescript code again for:
- services (
014400-AbpWebApiService.json
-batch) - rv-form
- rlist-form
- rdlist-form
- services (
- Regenerate
-
For
PhbkEmployee
-entity (direct master):- Regenerate
routing
-code again, as the routing items number has changed - Regenerate typescript code again for:
- services (
014400-AbpWebApiService.json
-batch) - rv-form
- rlist-form
- rdlist-form
- services (
- Regenerate
-
For
PhbkDivision
-entity:- Regenerate
routing
-code again, as the routing items number has changed
- Regenerate
-
For
PhbkEnterprise
-entity:- Regenerate
routing
-code again, as the routing items number has changed
- Regenerate
Modify route.provider.ts
-file as follows:
Click to show the code
import { RoutesService, eLayoutType } from '@abp/ng.core';
import { inject, provideAppInitializer } from '@angular/core';
export const APP_ROUTE_PROVIDER = [
provideAppInitializer(() => {
configureRoutes();
}),
];
function configureRoutes() {
const routes = inject(RoutesService);
routes.add([
{
path: '/',
name: '::Menu:Home',
iconClass: 'fas fa-home',
order: 1,
layout: eLayoutType.application,
},
{
path: '/RDLPhbkPhoneTypeDto',
name: 'Phone Type Dlg',
requiredPolicy: 'firstapp.PhbkPhoneTypeDto',
iconClass: 'fas fa-phone',
order: 20,
layout: eLayoutType.application,
},
{
path: '/PhbkPhoneTypeDto',
name: 'Phone Type',
requiredPolicy: 'firstapp.PhbkPhoneTypeDto',
iconClass: 'fas fa-phone',
order: 30,
layout: eLayoutType.application,
},
{
path: '/RDLPhbkFileDto',
name: 'Phone book file Dlg',
requiredPolicy: 'firstapp.PhbkFileDto',
iconClass: 'fas fa-file',
order: 40,
layout: eLayoutType.application,
},
{
path: '/PhbkFileDto',
name: 'Phone book file',
requiredPolicy: 'firstapp.PhbkFileDto',
iconClass: 'fas fa-file',
order: 50,
layout: eLayoutType.application,
},
{
name: 'firstapp::Psn:PhbkEnterpriseDto',
group: 'firstapp::Psn:PhbkEnterpriseDto',
order: 11,
iconClass: 'fas fa-building',
},
{
path: '/RDLPhbkEnterpriseDto',
name: 'Enterprise Dlg',
requiredPolicy: 'firstapp.PhbkEnterpriseDto',
iconClass: 'fas fa-building',
parentName: 'firstapp::Psn:PhbkEnterpriseDto',
order: 40,
layout: eLayoutType.application,
},
{
path: '/PhbkEnterpriseDto',
name: 'Enterprise',
requiredPolicy: 'firstapp.PhbkEnterpriseDto',
parentName: 'firstapp::Psn:PhbkEnterpriseDto',
iconClass: 'fas fa-building',
order: 50,
layout: eLayoutType.application,
},
{
name: 'firstapp::Psn:PhbkDivisionDto',
group: 'firstapp::Psn:PhbkDivisionDto',
order: 12,
iconClass: 'fas fa-building',
},
{
path: '/RDLPhbkDivisionDto',
name: 'Division Dlg',
requiredPolicy: 'firstapp.PhbkDivisionDto',
parentName: 'firstapp::Psn:PhbkDivisionDto',
iconClass: 'fas fa-building',
order: 60,
layout: eLayoutType.application,
},
{
path: '/PhbkDivisionDto',
name: 'Division',
requiredPolicy: 'firstapp.PhbkDivisionDto',
parentName: 'firstapp::Psn:PhbkDivisionDto',
iconClass: 'fas fa-building',
order: 70,
layout: eLayoutType.application,
},
{
name: 'firstapp::Psn:PhbkEmployeeDto',
group: 'firstapp::Psn:PhbkEmployeeDto',
order: 13,
iconClass: 'fas fa-user-tie',
},
{
path: '/RDLPhbkEmployeeDto',
name: 'Employee Dlg',
requiredPolicy: 'firstapp.PhbkEmployeeDto',
parentName: 'firstapp::Psn:PhbkEmployeeDto',
iconClass: 'fas fa-user-tie',
order: 80,
layout: eLayoutType.application,
},
{
path: '/PhbkEmployeeDto',
name: 'Employee',
requiredPolicy: 'firstapp.PhbkEmployeeDto',
parentName: 'firstapp::Psn:PhbkEmployeeDto',
iconClass: 'fas fa-user-tie',
order: 90,
layout: eLayoutType.application,
},
{
name: 'firstapp::Psn:PhbkPhoneDto',
group: 'firstapp::Psn:PhbkPhoneDto',
order: 14,
iconClass: 'fas fa-phone',
},
{
path: '/RDLPhbkPhoneDto',
name: 'Phone Dlg',
requiredPolicy: 'firstapp.PhbkPhoneDto',
parentName: 'firstapp::Psn:PhbkPhoneDto',
iconClass: 'fas fa-phone',
order: 100,
layout: eLayoutType.application,
},
{
path: '/PhbkPhoneDto',
name: 'Phone',
requiredPolicy: 'firstapp.PhbkPhoneDto',
parentName: 'firstapp::Psn:PhbkPhoneDto',
iconClass: 'fas fa-phone',
order: 110,
layout: eLayoutType.application,
}
]);
}