415 Fifth entity of ABP framework applications - chempkovsky/CS82ANGULAR GitHub Wiki

Note
Entity
  • In the Phbk folder of the rupbes.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

    }
}
Modify DBContext
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

project structure

  • Second foreign key will be as follows:
Click to show the picture

project structure

Dto
Click to show the picture

project structure

  • This is how the first prefix is ​​defined:
Click to show the picture

project structure

  • This is how the second prefix is ​​defined:
Click to show the picture

project structure

Web Api
  • 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 means DEEntrprsName-prop and DivisionName-prop will not be generated for DTO-class. This is because we are using the Apb-repo class.
Click to show the picture

project structure

Typescript Classes
Click to show the picture

project structure

  • UI Form properties is as follows:
Click to show the picture

project structure

  • EDEEntrprsName-prop and EDDivisionName-prop and PPhoneTypeName-prop have SearchDialog-input type even for Delete and View-forms. If we assign readonly or default-type for EDEEntrprsName-prop and EDDivisionName-prop and PPhoneTypeName-prop than they will not be displayed on Delete and View-forms.

  • Modify app-routing.module.ts-file for PhbkEmployee-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
  • 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
  • For PhbkDivision-entity:

    • Regenerate routing-code again, as the routing items number has changed
  • For PhbkEnterprise-entity:

    • Regenerate routing-code again, as the routing items number has changed

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,
      }


  ]);
}
⚠️ **GitHub.com Fallback** ⚠️