MyBookmark/Modules.User.Infrastructure.Database/Database/UserDbContext.cs

277 lines
11 KiB
C#

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.ValueGeneration;
using Modules.User.Database.Database.Entities;
namespace Modules.User.Database.Database;
public class UserDbContext : DbContext
{
public DbSet<Account> Accounts { get; set; }
public DbSet<Entities.User> Users { get; set; }
public DbSet<Session> Sessions { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<AccountRole> AccountRoles { get; set; }
public DbSet<Permission> Permissions { get; set; }
public DbSet<AccountPermission> AccountPermissions { get; set; }
public UserDbContext(DbContextOptions<UserDbContext> options) : base(options)
{
}
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder.Properties<Enum>().HaveConversion<string>();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Entities.User>(q =>
{
q.ToTable("Users");
q.HasKey(x => x.Id);
q.Property(x => x.NickName).IsRequired().HasMaxLength(32);
q.Property(x => x.FirstName).HasMaxLength(32);
q.Property(x => x.Patronymic).HasMaxLength(64);
q.Property(x => x.LastName).HasMaxLength(128);
q.Property(x => x.AvatarId).HasMaxLength(128);
q.HasOne(x => x.Account)
.WithOne(x => x.User)
.HasForeignKey<Account>(x => x.UserId);
q.Property(e => e.Xmin).HasColumnName("xmin").IsRowVersion();
q.OwnsOne(x => x.RegionalSettings);
});
modelBuilder.Entity<Entities.User>()
.Navigation(x => x.RegionalSettings).IsRequired(); //fix optional dependent
modelBuilder.Entity<Account>(q =>
{
q.ToTable("Accounts");
q.HasKey(x => x.Id);
q.Property(x => x.Email).IsRequired().HasMaxLength(128);
q.Property(x => x.HashedPassword).IsRequired().HasMaxLength(256);
q.HasMany(x => x.Sessions)
.WithOne()
.HasForeignKey(x => x.AccountId)
.OnDelete(DeleteBehavior.Cascade);
q.Property(x => x.CreationDate)
.HasDefaultValueSql("now()").ValueGeneratedOnAdd().HasValueGenerator(typeof(DatetimeNowValueGenerator));
q.Property(e => e.Xmin).HasColumnName("xmin").IsRowVersion();
});
modelBuilder.Entity<Session>(q =>
{
//q.Property(q => q.DeviceInfo).HasMaxLength(128);
//q.Property(q => q.UserAgent).HasMaxLength(128);
q.OwnsOne(x => x.ClientInfo, x =>
{
x.Property(z => z.UserAgent).HasMaxLength(256);
x.Property(z => z.Country).HasMaxLength(96);
x.Property(z => z.Region).HasMaxLength(128);
});
q.Property(x => x.RefreshToken).IsRequired().HasMaxLength(172); //128 bytes to base64
// q.Property(x => x.ExpiredDate).HasDefaultValueSql("'0001-01-01 00:00:00+00'").ValueGeneratedOnAdd();
q.Property(x => x.ExpiredDate).HasDefaultValueSql("now()").ValueGeneratedOnAdd();
q.Property(x => x.LastUpdate).HasDefaultValueSql("now()").ValueGeneratedOnAdd();
});
modelBuilder.Entity<Permission>(q =>
{
q.ToTable("Permissions");
q.HasKey(x => x.Id);
q.Property(x => x.Code).IsRequired().HasMaxLength(128);
q.HasIndex(x => x.Code).IsUnique();
q.Property(x => x.Name).IsRequired().HasMaxLength(64);
q.Property(x => x.Description).HasMaxLength(512);
q.Property(x => x.CreationDate)
.HasDefaultValueSql("now()").ValueGeneratedOnAdd().HasValueGenerator(typeof(DatetimeNowValueGenerator));
q.Property(e => e.Xmin).HasColumnName("xmin").IsRowVersion();
});
modelBuilder.Entity<Role>(q =>
{
q.ToTable("Roles");
q.HasKey(x => x.Id);
q.Property(x => x.Code).IsRequired().HasMaxLength(64);
q.HasIndex(x => x.Code).IsUnique();
q.Property(x => x.Name).IsRequired().HasMaxLength(32);
q.Property(x => x.Description).HasMaxLength(512);
q.Property(x => x.CreationDate)
.HasDefaultValueSql("now()").ValueGeneratedOnAdd().HasValueGenerator(typeof(DatetimeNowValueGenerator));
q.Property(e => e.Xmin).HasColumnName("xmin").IsRowVersion();
q.HasMany(x => x.Permissions)
.WithMany(x => x.Roles)
.UsingEntity<Dictionary<string, object>>("RolePermissions",
x => x.HasOne<Permission>()
.WithMany()
.HasForeignKey("PermissionId")
.OnDelete(DeleteBehavior.Restrict)
, x => x.HasOne<Role>()
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Restrict),
x =>
{
x.ToTable("RolePermissions");
x.HasKey("RoleId", "PermissionId");
});
});
modelBuilder.Entity<AccountRole>(q =>
{
q.ToTable("AccountRoles");
q.HasKey(x => x.Id);
q.Property(x => x.GrantedAtUtc)
.HasDefaultValueSql("now()").ValueGeneratedOnAdd().HasValueGenerator(typeof(DatetimeNowValueGenerator));
q.Property(x => x.IssuerId).IsRequired();
q.Property(x => x.RevokedAtUtc).IsRequired(false);
q.Property(x => x.GrantReason).IsRequired(false).HasMaxLength(128);
q.Property(x => x.RevokeReason).IsRequired(false).HasMaxLength(128);
q.Property(e => e.Xmin).HasColumnName("xmin").IsRowVersion();
q.HasOne(x => x.Account)
.WithMany(a => a.Roles)
.HasForeignKey(x => x.AccountId)
.OnDelete(DeleteBehavior.Restrict);
q.HasOne(x => x.Role)
.WithMany()
.HasForeignKey(x => x.RoleId)
.OnDelete(DeleteBehavior.Restrict);
q.HasOne(x => x.Issuer)
.WithMany()
.HasForeignKey(x => x.IssuerId)
.OnDelete(DeleteBehavior.Restrict);
q.HasOne(x => x.Revoker)
.WithMany()
.HasForeignKey(x => x.RevokerId)
.OnDelete(DeleteBehavior.Restrict)
.IsRequired(false);
q.HasIndex(x => new { x.AccountId, x.RoleId })
.HasDatabaseName("UX_AccountRoles_Active")
.IsUnique()
.HasFilter("\"RevokedAtUtc\" IS NULL");
q.HasIndex(x => new { x.AccountId, x.GrantedAtUtc });
q.HasIndex(x => new { x.IssuerId, x.GrantedAtUtc });
});
modelBuilder.Entity<AccountPermission>(q =>
{
q.ToTable("AccountPermissions");
q.HasKey(x => x.Id);
q.Property(x => x.GrantedAtUtc)
.HasDefaultValueSql("now()").ValueGeneratedOnAdd().HasValueGenerator(typeof(DatetimeNowValueGenerator));
q.Property(x => x.IssuerId).IsRequired();
q.Property(x => x.RevokedAtUtc).IsRequired(false);
q.Property(x => x.GrantReason).IsRequired(false).HasMaxLength(128);
q.Property(x => x.RevokeReason).IsRequired(false).HasMaxLength(128);
q.Property(e => e.Xmin).HasColumnName("xmin").IsRowVersion();
q.HasOne(x => x.Account)
.WithMany(a => a.Permissions)
.HasForeignKey(x => x.AccountId)
.OnDelete(DeleteBehavior.Restrict);
q.HasOne(x => x.Permission)
.WithMany()
.HasForeignKey(x => x.PermissionId)
.OnDelete(DeleteBehavior.Restrict);
q.HasOne(x => x.Issuer)
.WithMany()
.HasForeignKey(x => x.IssuerId)
.OnDelete(DeleteBehavior.Restrict);
q.HasOne(x => x.Revoker)
.WithMany()
.HasForeignKey(x => x.RevokerId)
.OnDelete(DeleteBehavior.Restrict)
.IsRequired(false);
q.HasIndex(x => new { x.AccountId, x.PermissionId })
.HasDatabaseName("UX_AccountPermissions_Active")
.IsUnique()
.HasFilter("\"RevokedAtUtc\" IS NULL");
q.HasIndex(x => new { x.AccountId, x.GrantedAtUtc });
q.HasIndex(x => new { x.IssuerId, x.GrantedAtUtc });
});
modelBuilder.Entity<AccountBan>(q =>
{
q.ToTable("AccountBans");
q.HasKey(x => x.Id);
q.Property(x => x.BanDate)
.HasDefaultValueSql("now()").ValueGeneratedOnAdd().HasValueGenerator(typeof(DatetimeNowValueGenerator));
q.Property(x => x.IssuerId).IsRequired();
q.Property(x => x.Reason).IsRequired().HasMaxLength(128);
q.Property(x => x.UnbanReason).IsRequired(false).HasMaxLength(128);
q.Property(e => e.Xmin).HasColumnName("xmin").IsRowVersion();
q.HasOne(x => x.Account)
.WithMany(a => a.Bans)
.HasForeignKey(x => x.AccountId)
.OnDelete(DeleteBehavior.Restrict);
q.HasIndex(x => new { x.AccountId, x.BanDate });
// q.HasIndex(x => new { x.AccountId, x.ReleaseDate })
// .HasDatabaseName("IX_AccountBans_Active")
// .HasFilter("\"Deleted\" = false AND (\"ReleaseDate\" IS NULL OR \"ReleaseDate\" > now())");
});
RolesAndPermissionSeedList.SeedPermissions(modelBuilder.Entity<Permission>());
RolesAndPermissionSeedList.SeedRoles(modelBuilder.Entity<Role>(), modelBuilder);
modelBuilder.Entity<Account>().HasQueryFilter(x => !x.Deleted);
modelBuilder.Entity<AccountPermission>().HasQueryFilter(x => !x.Account.Deleted);
modelBuilder.Entity<AccountRole>().HasQueryFilter(x => !x.Account.Deleted);
modelBuilder.Entity<AccountBan>().HasQueryFilter(x => !x.Deleted);
modelBuilder.Entity<Role>().HasQueryFilter(x => !x.Deleted);
modelBuilder.Entity<Permission>().HasQueryFilter(x => !x.Deleted);
}
private class DatetimeNowValueGenerator : ValueGenerator<DateTime>
{
public override bool GeneratesTemporaryValues => false;
public override DateTime Next(EntityEntry entry)
{
return DateTime.UtcNow;
}
}
}