413 Third 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 PhbkDivision : Entity<int>, IMultiTenant, IHasConcurrencyStamp
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        [Display(Description = "Row id", Name = "Id of the Division", Prompt = "Enter Division Id", ShortName = "Division Id")]
        [Required]
        public override int Id { get; protected set; }

        [Display(Description = "Name of the Enterprise Division", Name = "Name of the Division", Prompt = "Enter Division Name", ShortName = "Division Name")]
        [StringLength(20, MinimumLength = 3, ErrorMessage = "Invalid")]
        [Required]
        public string DivisionName { get; set; } = null!;

        [Display(Description = "Description of the Enterprise Division", Name = "Description of the Division", Prompt = "Enter Enterprise Division Description", ShortName = "Division Description")]
        [StringLength(250, ErrorMessage = "Invalid")]
        public string? DivisionDesc { get; 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; }


        [Display(Description = "Row id", Name = "Id of the Enterprise", Prompt = "Enter Enterprise  Id", ShortName = "Enterprise Id")]
        [Required]
        public int EntrprsIdRef { get; set; }

#if (!NOTMODELING)
        public PhbkEnterprise Enterprise { get; set; } = null!;
#endif

        public PhbkDivision() : base()
        {
            ConcurrencyStamp = Guid.NewGuid().ToString("N");
        }

        public PhbkDivision(int id, string divisionName, string? divisionDesc, int entrprsIdRef) : base(id)
        {
            Check.NotNullOrWhiteSpace(divisionName, nameof(DivisionName));
            DivisionName = divisionName;
            DivisionDesc = divisionDesc;
            EntrprsIdRef = entrprsIdRef;
            ConcurrencyStamp = Guid.NewGuid().ToString("N");
        }

        public virtual void ChangeVals(string divisionName, string? divisionDesc, int entrprsIdRef, string concurrencyStamp)
        {
            Check.NotNullOrWhiteSpace(divisionName, nameof(DivisionName));
            DivisionName = divisionName;
            DivisionDesc = divisionDesc;
            EntrprsIdRef = entrprsIdRef;
            ConcurrencyStamp = concurrencyStamp;
        }

    }
}
  • We have to modify PhbkEnterprise-class as well.
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 PhbkEnterprise : Entity<int>, IMultiTenant, IHasConcurrencyStamp
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        [Display(Description = "Row id", Name = "Id of the Enterprise", Prompt = "Enter Enterprise  Id", ShortName = "Enterprise Id")]
        [Required]
        public override int Id { get; protected set; } = default!;

        [Display(Description = "Name of the Enterprise", Name = "Name of the Enterprise", Prompt = "Enter Enterprise Name", ShortName = "Enterprise Name")]
        [StringLength(20, MinimumLength = 3, ErrorMessage = "Invalid")]
        [Required]
        public string EntrprsName { get; protected set; } = null!;

        [Display(Description = "Description of the Enterprise", Name = "Description of the Enterprise", Prompt = "Description Enterprise Name", ShortName = "Enterprise Description")]
        [StringLength(250, ErrorMessage = "Invalid")]
        public string? EntrprsDesc { 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 PhbkEnterprise() : base()
        {
            ConcurrencyStamp = Guid.NewGuid().ToString("N");
        }

        public PhbkEnterprise(int id, string entrprsName, string? entrprsDesc) : base(id)
        {
            Check.NotNullOrWhiteSpace(entrprsName, nameof(EntrprsName));
            EntrprsName = entrprsName;
            EntrprsDesc = entrprsDesc;
            ConcurrencyStamp = Guid.NewGuid().ToString("N");
        }

        public virtual void ChangeVals(string entrprsName, string? entrprsDesc, string concurrencyStamp)
        {
            Check.NotNullOrWhiteSpace(entrprsName, nameof(EntrprsName));
            EntrprsName = entrprsName;
            EntrprsDesc = entrprsDesc;
            ConcurrencyStamp = concurrencyStamp;
        }

#if (!NOTMODELING)
        public virtual List<PhbkDivision> Divisions { 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<PhbkPhoneType>().HasKey(p => p.Id);
        builder.Entity<PhbkEnterprise>().HasKey(p => p.Id);
        builder.Entity<PhbkDivision>().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);
#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);
            });

        }
    }

Please take a look at b.HasOne<PhbkEnterprise>()-operator. We declare foreign key without using .WithMany(m => m.Divisions) and .HasOne(d => d.Enterprise) operators since Enterprise-property and Divisions-property declared to be used only at modeling time

#if (!NOTMODELING)
        public PhbkEnterprise Enterprise { get; set; } = null!;
#endif

...

#if (!NOTMODELING)
        public virtual List<PhbkDivision> Divisions { get; set; } = null!;

#endif
  • 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 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 EEntrprsName-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

  • EEntrprsName-prop has SearchDialog-input type even for Delete and View-forms. We we assign readonly or default-type for EEntrprsName-prop than it will not be displayed on Delete and View-forms.

  • Modify app-routing.module.ts-file for PhbkDivision-entity as before.

  • For PhbkEnterprise-entity:

    • 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

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


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