Skip to content

DataLayer

meliora-solution edited this page Jan 31, 2024 · 7 revisions

In the DataLayer I created three projects.

  • CodeFirstDbDesign. This project is blazor application for creating Migration and Update database for IdentityUser100 and EasyStockDb class projects.
  • IdentityUser100. This project will be used by UserManagement project to create UserIdentity tables.
  • EasyStockDb. This project create EasyStockContextDb for creating tables for EasyStock Project.

Database Contexts.

There Are two database contexts created for the implementation of Authp.

IdentityUser100DbContext

namespace IdentityUser100.Context
{
    public partial class IdentityUser100DbContext : IdentityDbContext
    {
        public IdentityUser100DbContext(DbContextOptions<IdentityUser100DbContext> options) : base(options)
        {

        }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.ApplyConfiguration(new ApplicationUserConfig());
            modelBuilder.ApplyConfiguration(new PropertyConfig());
            modelBuilder.ApplyConfiguration(new UserPropertyConfig());
            base.OnModelCreating(modelBuilder);
        }
        public DbSet<ApplicationUser> ApplicationUsers { get; set; }
        public DbSet<Property> Properties { get; set; }
        public DbSet<UserProperty> UserProperties { get; set; }

    }
}

ApplicationUserConfig

namespace IdentityUser100.Configuration
{
    public class ApplicationUserConfig : IEntityTypeConfiguration<ApplicationUser>
    {
        public void Configure(EntityTypeBuilder<ApplicationUser> builder)
        {

            builder.Property(b => b.Id).HasColumnType("varchar(256)");
            builder.Property(b => b.UserName).HasColumnType("varchar(256)");
            builder.Property(b => b.NormalizedUserName).HasColumnType("varchar(256)");
            builder.Property(b => b.Email).HasColumnType("varchar(256)");
            builder.Property(b => b.NormalizedEmail).HasColumnType("varchar(256)");
            builder.Property(b => b.PasswordHash).HasColumnType("varchar(256)");
            builder.Property(b => b.SecurityStamp).HasColumnType("varchar(256)");
            builder.Property(b => b.ConcurrencyStamp).HasColumnType("varchar(256)");
            builder.Property(b => b.PhoneNumber).HasColumnType("varchar(16)");
            builder.Property(b => b.Name).HasColumnType("varchar(100)");

            builder.Property(b => b.DateCreated).HasDefaultValueSql("GETDATE()");

        }
    }
}

This builder.Property(b => b.DateCreated).HasDefaultValueSql("GETDATE()"); will create timestamp to a new record.

EasyStockDbContext

namespace EasyStockDb.Context
{
    public class EasyStockDbContext : DbContext, IDataKeyFilterReadOnly
    {
        public string DataKey { get; }

        public EasyStockDbContext(DbContextOptions<EasyStockDbContext> options, IGetDataKeyFromUser dataKeyFilter) : base(options)
        {
            // The DataKey is null when: no one is logged in, its a background service, or user hasn't got an assigned tenant
            // In these cases its best to set the data key that doesn't match any possible DataKey 
            DataKey = dataKeyFilter?.DataKey ?? "Bad key";
        }

        public DbSet<Contact> Contacts { get; set; }
        public DbSet<ProductCategory> ProductCategories { get; set; } = null!;
        public DbSet<Product> Products { get; set; } = null!;
        public DbSet<ProductTransfer> ProductTransfers { get; set; } = null!;
        public DbSet<ProductUnit> ProductUnits { get; set; } = null!;
        public DbSet<Stock> stocks { get; set; } = null!;
        public DbSet<Store> Stores { get; set; } = null!;
        public DbSet<Transaction> Transactions { get; set; } = null!;
        public DbSet<TransactionLine> TransactionLines { get; set; } = null!;


        public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess,
       CancellationToken cancellationToken = default(CancellationToken))
        {
            this.MarkWithDataKeyIfNeeded(DataKey);
            return await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
        }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {

            modelBuilder.HasDefaultSchema("EasyStock");

      
            modelBuilder.ApplyConfiguration(new ContactConfig());
            modelBuilder.ApplyConfiguration(new ProductConfig());
            modelBuilder.ApplyConfiguration(new ProductCategoryConfig());
            modelBuilder.ApplyConfiguration(new ProductTransferConfig());
            modelBuilder.ApplyConfiguration(new ProductUnitConfig());
            modelBuilder.ApplyConfiguration(new StockConfig());
            modelBuilder.ApplyConfiguration(new StoreConfig());
            modelBuilder.ApplyConfiguration(new TransactionConfig());
            modelBuilder.ApplyConfiguration(new TransactionLineConfig());


            base.OnModelCreating(modelBuilder);

            foreach (var entityType in modelBuilder.Model.GetEntityTypes())
            {
                if (typeof(IDataKeyFilterReadWrite).IsAssignableFrom(entityType.ClrType))
                {
                    entityType.AddSingleTenantReadWriteQueryFilter(this);
                }
                else
                {
                    throw new Exception(
                        $"You haven't added the {nameof(IDataKeyFilterReadWrite)} to the entity {entityType.ClrType.Name}");
                }

                foreach (var mutableProperty in entityType.GetProperties())
                {
                    if (mutableProperty.ClrType == typeof(decimal))
                    {
                        mutableProperty.SetPrecision(9);
                        mutableProperty.SetScale(2);
                    }
                }
            }
        }
    }
}

Multitenant Contact Entity Design.

For every Entity class needs inherit form IDataKeyFilterReadWrite. This interface plays a crucial role in implementing multitenancy features

namespace EasyStockDb.Entity
{
    public class Contact : IDataKeyFilterReadWrite
    {
        public int ContactId { get; set; }

        public string type { get; set; }

        public string Name { get; set; }
        public string Address { get; set; }
        public string Phone { get; set; }
        public string Description { get; set; }
        public string DataKey { get; set; }

        public ICollection<Transaction> Transactions { get; set; }
    }

}

Clone this wiki locally