522 lines
24 KiB
C#
522 lines
24 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace GreenHome.Infrastructure.Data;
|
|
|
|
public sealed class GreenHomeDbContext : DbContext
|
|
{
|
|
public GreenHomeDbContext(DbContextOptions<GreenHomeDbContext> options) : base(options) { }
|
|
|
|
public DbSet<Domain.Device> Devices => Set<Domain.Device>();
|
|
public DbSet<Domain.TelemetryRecord> TelemetryRecords => Set<Domain.TelemetryRecord>();
|
|
public DbSet<Domain.DeviceSettings> DeviceSettings => Set<Domain.DeviceSettings>();
|
|
public DbSet<Domain.AlertCondition> AlertConditions => Set<Domain.AlertCondition>();
|
|
public DbSet<Domain.AlertRule> AlertRules => Set<Domain.AlertRule>();
|
|
public DbSet<Domain.DeviceRelay> DeviceRelays => Set<Domain.DeviceRelay>();
|
|
public DbSet<Domain.RelayRuleGroup> RelayRuleGroups => Set<Domain.RelayRuleGroup>();
|
|
public DbSet<Domain.RelayRuleCondition> RelayRuleConditions => Set<Domain.RelayRuleCondition>();
|
|
public DbSet<Domain.User> Users => Set<Domain.User>();
|
|
public DbSet<Domain.VerificationCode> VerificationCodes => Set<Domain.VerificationCode>();
|
|
public DbSet<Domain.DeviceUser> DeviceUsers => Set<Domain.DeviceUser>();
|
|
public DbSet<Domain.AlertNotification> AlertNotifications => Set<Domain.AlertNotification>();
|
|
public DbSet<Domain.AlertLog> AlertLogs => Set<Domain.AlertLog>();
|
|
public DbSet<Domain.AIQuery> AIQueries => Set<Domain.AIQuery>();
|
|
public DbSet<Domain.AIProfile> AIProfiles => Set<Domain.AIProfile>();
|
|
public DbSet<Domain.DailyReport> DailyReports => Set<Domain.DailyReport>();
|
|
public DbSet<Domain.UserDailyReport> UserDailyReports => Set<Domain.UserDailyReport>();
|
|
public DbSet<Domain.ReportImage> ReportImages => Set<Domain.ReportImage>();
|
|
public DbSet<Domain.Checklist> Checklists => Set<Domain.Checklist>();
|
|
public DbSet<Domain.ChecklistItem> ChecklistItems => Set<Domain.ChecklistItem>();
|
|
public DbSet<Domain.ChecklistCompletion> ChecklistCompletions => Set<Domain.ChecklistCompletion>();
|
|
public DbSet<Domain.ChecklistItemCompletion> ChecklistItemCompletions => Set<Domain.ChecklistItemCompletion>();
|
|
public DbSet<Domain.DevicePost> DevicePosts => Set<Domain.DevicePost>();
|
|
public DbSet<Domain.DevicePostImage> DevicePostImages => Set<Domain.DevicePostImage>();
|
|
public DbSet<Domain.PowerOutageLog> PowerOutageLogs => Set<Domain.PowerOutageLog>();
|
|
public DbSet<Domain.UsageCounter> UsageCounters => Set<Domain.UsageCounter>();
|
|
public DbSet<Domain.AdminAuditLog> AdminAuditLogs => Set<Domain.AdminAuditLog>();
|
|
|
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
{
|
|
base.OnModelCreating(modelBuilder);
|
|
|
|
modelBuilder.Entity<Domain.Device>(b =>
|
|
{
|
|
b.ToTable("Devices");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.DeviceName).IsRequired().HasMaxLength(10);
|
|
b.Property(x => x.UserId).IsRequired();
|
|
b.Property(x => x.Location).HasMaxLength(250);
|
|
b.Property(x => x.NeshanLocation).HasMaxLength(80);
|
|
b.HasOne(x => x.User)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.UserId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.TelemetryRecord>(b =>
|
|
{
|
|
b.ToTable("Telemetry");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.TemperatureC).HasColumnType("decimal(18,2)");
|
|
b.Property(x => x.HumidityPercent).HasColumnType("decimal(18,2)");
|
|
b.Property(x => x.SoilPercent).HasColumnType("decimal(18,2)");
|
|
b.Property(x => x.Lux).HasColumnType("decimal(18,2)");
|
|
b.Property(x => x.PersianDate).HasMaxLength(10);
|
|
b.Property(x => x.Voltage).HasColumnType("decimal(18,2)");
|
|
b.Property(x => x.BatteryVoltage).HasColumnType("decimal(18,2)");
|
|
b.Property(x => x.BatteryPercent).HasColumnType("decimal(18,2)");
|
|
b.Property(x => x.RelayStates).HasMaxLength(64);
|
|
b.HasIndex(x => new { x.DeviceId, x.PersianYear, x.PersianMonth });
|
|
b.HasIndex(x => new { x.DeviceId, x.TimestampUtc });
|
|
b.HasIndex(x => new { x.DeviceId, x.ServerTimestampUtc });
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.DeviceSettings>(b =>
|
|
{
|
|
b.ToTable("DeviceSettings");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.Province).HasMaxLength(100);
|
|
b.Property(x => x.City).HasMaxLength(100);
|
|
b.Property(x => x.Latitude).HasColumnType("decimal(9,6)");
|
|
b.Property(x => x.Longitude).HasColumnType("decimal(9,6)");
|
|
b.Property(x => x.ProductType).HasMaxLength(100);
|
|
b.Property(x => x.MinimumSmsIntervalMinutes).HasDefaultValue(15);
|
|
b.Property(x => x.MinimumCallIntervalMinutes).HasDefaultValue(60);
|
|
b.Property(x => x.AreaSquareMeters).HasColumnType("decimal(18,2)");
|
|
b.Property(x => x.SmsRecievers).HasMaxLength(120);
|
|
b.Property(x => x.RelayCount).HasDefaultValue(4);
|
|
b.HasOne(x => x.Device)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.DeviceId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
b.HasIndex(x => x.DeviceId).IsUnique();
|
|
b.HasMany(x => x.Relays)
|
|
.WithOne(r => r.DeviceSettings)
|
|
.HasForeignKey(r => r.DeviceSettingsId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.DeviceRelay>(b =>
|
|
{
|
|
b.ToTable("DeviceRelays");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.RelayIndex).IsRequired();
|
|
b.Property(x => x.Name).HasMaxLength(100);
|
|
b.Property(x => x.RelayKind).IsRequired().HasConversion<int>();
|
|
b.HasIndex(x => new { x.DeviceSettingsId, x.RelayIndex }).IsUnique();
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.RelayRuleGroup>(b =>
|
|
{
|
|
b.ToTable("RelayRuleGroups");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.Action).IsRequired().HasConversion<int>();
|
|
b.Property(x => x.Label).HasMaxLength(200);
|
|
b.Property(x => x.Order).IsRequired();
|
|
b.HasOne(x => x.DeviceRelay)
|
|
.WithMany(r => r.RuleGroups)
|
|
.HasForeignKey(x => x.DeviceRelayId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
b.HasIndex(x => x.DeviceRelayId);
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.RelayRuleCondition>(b =>
|
|
{
|
|
b.ToTable("RelayRuleConditions");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.ConditionType).IsRequired().HasConversion<int>();
|
|
b.Property(x => x.SensorType).HasConversion<int>();
|
|
b.Property(x => x.ComparisonType).HasConversion<int>();
|
|
b.Property(x => x.Value1).HasColumnType("decimal(18,2)");
|
|
b.Property(x => x.Value2).HasColumnType("decimal(18,2)");
|
|
b.Property(x => x.Order).IsRequired();
|
|
b.HasOne(x => x.RelayRuleGroup)
|
|
.WithMany(g => g.Conditions)
|
|
.HasForeignKey(x => x.RelayRuleGroupId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
b.HasIndex(x => x.RelayRuleGroupId);
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.AlertCondition>(b =>
|
|
{
|
|
b.ToTable("AlertConditions");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.NotificationType).IsRequired().HasConversion<int>();
|
|
b.Property(x => x.TimeType).IsRequired().HasConversion<int>();
|
|
b.Property(x => x.CallCooldownMinutes).IsRequired();
|
|
b.Property(x => x.SmsCooldownMinutes).IsRequired();
|
|
b.Property(x => x.IsEnabled).IsRequired();
|
|
b.HasOne(x => x.Device)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.DeviceId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
b.HasIndex(x => x.DeviceId);
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.AlertRule>(b =>
|
|
{
|
|
b.ToTable("AlertRules");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.SensorType).IsRequired().HasConversion<int>();
|
|
b.Property(x => x.ComparisonType).IsRequired().HasConversion<int>();
|
|
b.Property(x => x.Value1).IsRequired().HasColumnType("decimal(18,2)");
|
|
b.Property(x => x.Value2).HasColumnType("decimal(18,2)");
|
|
b.Property(x => x.Order).IsRequired();
|
|
b.HasOne(x => x.AlertCondition)
|
|
.WithMany(c => c.Rules)
|
|
.HasForeignKey(x => x.AlertConditionId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
b.HasIndex(x => x.AlertConditionId);
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.User>(b =>
|
|
{
|
|
b.ToTable("Users");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.Mobile).IsRequired().HasMaxLength(11);
|
|
b.Property(x => x.Name).IsRequired().HasMaxLength(100);
|
|
b.Property(x => x.Family).IsRequired().HasMaxLength(100);
|
|
b.Property(x => x.Role).IsRequired().HasConversion<int>();
|
|
b.HasIndex(x => x.Mobile).IsUnique();
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.DeviceUser>(b =>
|
|
{
|
|
b.ToTable("DeviceUsers");
|
|
b.HasKey(x => new { x.DeviceId, x.UserId });
|
|
b.Property(x => x.ReceiveAlerts).IsRequired().HasDefaultValue(true);
|
|
b.Property(x => x.Role).IsRequired().HasConversion<int>();
|
|
b.Property(x => x.Name).IsRequired().HasMaxLength(100);
|
|
b.Property(x => x.Family).IsRequired().HasMaxLength(100);
|
|
b.Property(x => x.AvatarPath).HasMaxLength(500);
|
|
b.HasOne(x => x.Device)
|
|
.WithMany(d => d.DeviceUsers)
|
|
.HasForeignKey(x => x.DeviceId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
b.HasOne(x => x.User)
|
|
.WithMany(u => u.DeviceUsers)
|
|
.HasForeignKey(x => x.UserId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.VerificationCode>(b =>
|
|
{
|
|
b.ToTable("VerificationCodes");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.Mobile).IsRequired().HasMaxLength(11);
|
|
b.Property(x => x.Code).IsRequired().HasMaxLength(4);
|
|
b.HasIndex(x => new { x.Mobile, x.Code, x.IsUsed });
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.AlertNotification>(b =>
|
|
{
|
|
b.ToTable("AlertNotifications");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.NotificationType).IsRequired().HasConversion<int>();
|
|
b.Property(x => x.Message).IsRequired().HasMaxLength(500);
|
|
b.Property(x => x.MessageOutboxIds).HasMaxLength(500);
|
|
b.Property(x => x.ErrorMessage).HasMaxLength(1000);
|
|
b.HasOne(x => x.Device)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.DeviceId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
b.HasOne(x => x.User)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.UserId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
b.HasOne(x => x.AlertCondition)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.AlertConditionId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
b.HasIndex(x => new { x.DeviceId, x.UserId, x.AlertConditionId, x.SentAt });
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.AIQuery>(b =>
|
|
{
|
|
b.ToTable("AIQueries");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.Question).IsRequired();
|
|
b.Property(x => x.Answer).IsRequired();
|
|
b.Property(x => x.Model).HasMaxLength(100);
|
|
b.Property(x => x.CostUsd).HasColumnType("decimal(18,8)");
|
|
b.HasOne(x => x.Device)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.DeviceId)
|
|
.OnDelete(DeleteBehavior.SetNull);
|
|
b.HasOne(x => x.User)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.UserId)
|
|
.OnDelete(DeleteBehavior.SetNull);
|
|
b.HasOne(x => x.Profile)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.ProfileId)
|
|
.OnDelete(DeleteBehavior.SetNull);
|
|
b.HasIndex(x => x.DeviceId);
|
|
b.HasIndex(x => x.UserId);
|
|
b.HasIndex(x => x.ProfileId);
|
|
b.HasIndex(x => x.CreatedAt);
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.AIProfile>(b =>
|
|
{
|
|
b.ToTable("AIProfiles");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.Name).IsRequired().HasMaxLength(100);
|
|
b.Property(x => x.Provider).IsRequired().HasConversion<int>();
|
|
b.Property(x => x.BaseUrl).IsRequired().HasMaxLength(300);
|
|
b.Property(x => x.ApiKey).IsRequired().HasMaxLength(500);
|
|
b.Property(x => x.Model).IsRequired().HasMaxLength(100);
|
|
b.Property(x => x.PromptPricePer1M).HasColumnType("decimal(18,6)");
|
|
b.Property(x => x.CompletionPricePer1M).HasColumnType("decimal(18,6)");
|
|
b.Property(x => x.BalanceUsd).HasColumnType("decimal(18,6)");
|
|
b.Property(x => x.BalanceCurrency).HasMaxLength(10);
|
|
b.HasIndex(x => x.IsActive);
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.DailyReport>(b =>
|
|
{
|
|
b.ToTable("DailyReports");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.PersianDate).IsRequired().HasMaxLength(10);
|
|
b.Property(x => x.Analysis).IsRequired();
|
|
b.Property(x => x.Model).HasMaxLength(100);
|
|
b.HasOne(x => x.Device)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.DeviceId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
b.HasIndex(x => new { x.DeviceId, x.PersianDate }).IsUnique();
|
|
b.HasIndex(x => new { x.DeviceId, x.PersianYear, x.PersianMonth });
|
|
b.HasIndex(x => x.CreatedAt);
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.AlertLog>(b =>
|
|
{
|
|
b.ToTable("AlertLogs");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.AlertType).IsRequired().HasConversion<int>();
|
|
b.Property(x => x.NotificationType).IsRequired().HasConversion<int>();
|
|
b.Property(x => x.Message).IsRequired().HasMaxLength(1000);
|
|
b.Property(x => x.Status).IsRequired().HasConversion<int>();
|
|
b.Property(x => x.ErrorMessage).HasMaxLength(2000);
|
|
b.Property(x => x.PhoneNumber).IsRequired().HasMaxLength(20);
|
|
b.HasOne(x => x.Device)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.DeviceId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
b.HasOne(x => x.User)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.UserId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
b.HasOne(x => x.AlertCondition)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.AlertConditionId)
|
|
.OnDelete(DeleteBehavior.SetNull);
|
|
b.HasIndex(x => new { x.DeviceId, x.SentAt });
|
|
b.HasIndex(x => new { x.UserId, x.SentAt });
|
|
b.HasIndex(x => x.AlertType);
|
|
b.HasIndex(x => x.Status);
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.UserDailyReport>(b =>
|
|
{
|
|
b.ToTable("UserDailyReports");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.PersianDate).IsRequired().HasMaxLength(10);
|
|
b.Property(x => x.Title).IsRequired().HasMaxLength(200);
|
|
b.Property(x => x.Observations).IsRequired();
|
|
b.Property(x => x.Operations).IsRequired();
|
|
b.Property(x => x.Notes).HasMaxLength(2000);
|
|
b.HasOne(x => x.Device)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.DeviceId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
b.HasOne(x => x.User)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.UserId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
b.HasIndex(x => new { x.DeviceId, x.PersianDate });
|
|
b.HasIndex(x => new { x.DeviceId, x.PersianYear, x.PersianMonth });
|
|
b.HasIndex(x => x.UserId);
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.ReportImage>(b =>
|
|
{
|
|
b.ToTable("ReportImages");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.FileName).IsRequired().HasMaxLength(255);
|
|
b.Property(x => x.FilePath).IsRequired().HasMaxLength(500);
|
|
b.Property(x => x.ContentType).IsRequired().HasMaxLength(100);
|
|
b.Property(x => x.Description).HasMaxLength(500);
|
|
b.HasOne(x => x.UserDailyReport)
|
|
.WithMany(r => r.Images)
|
|
.HasForeignKey(x => x.UserDailyReportId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
b.HasIndex(x => x.UserDailyReportId);
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.Checklist>(b =>
|
|
{
|
|
b.ToTable("Checklists");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.Title).IsRequired().HasMaxLength(200);
|
|
b.Property(x => x.Description).HasMaxLength(1000);
|
|
b.Property(x => x.IsActive).IsRequired();
|
|
b.HasOne(x => x.Device)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.DeviceId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
b.HasOne(x => x.CreatedByUser)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.CreatedByUserId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
b.HasIndex(x => new { x.DeviceId, x.IsActive });
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.ChecklistItem>(b =>
|
|
{
|
|
b.ToTable("ChecklistItems");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.Title).IsRequired().HasMaxLength(300);
|
|
b.Property(x => x.Description).HasMaxLength(1000);
|
|
b.Property(x => x.Order).IsRequired();
|
|
b.Property(x => x.IsRequired).IsRequired();
|
|
b.HasOne(x => x.Checklist)
|
|
.WithMany(c => c.Items)
|
|
.HasForeignKey(x => x.ChecklistId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
b.HasIndex(x => new { x.ChecklistId, x.Order });
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.ChecklistCompletion>(b =>
|
|
{
|
|
b.ToTable("ChecklistCompletions");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.PersianDate).IsRequired().HasMaxLength(10);
|
|
b.Property(x => x.Notes).HasMaxLength(2000);
|
|
b.HasOne(x => x.Checklist)
|
|
.WithMany(c => c.Completions)
|
|
.HasForeignKey(x => x.ChecklistId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
b.HasOne(x => x.CompletedByUser)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.CompletedByUserId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
b.HasIndex(x => new { x.ChecklistId, x.PersianDate });
|
|
b.HasIndex(x => x.CompletedByUserId);
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.ChecklistItemCompletion>(b =>
|
|
{
|
|
b.ToTable("ChecklistItemCompletions");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.IsChecked).IsRequired();
|
|
b.Property(x => x.Note).HasMaxLength(500);
|
|
b.HasOne(x => x.ChecklistCompletion)
|
|
.WithMany(cc => cc.ItemCompletions)
|
|
.HasForeignKey(x => x.ChecklistCompletionId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
b.HasOne(x => x.ChecklistItem)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.ChecklistItemId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
b.HasIndex(x => x.ChecklistCompletionId);
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.DevicePost>(b =>
|
|
{
|
|
b.ToTable("DevicePosts");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.Content).IsRequired().HasMaxLength(5000);
|
|
b.Property(x => x.PostType).IsRequired().HasConversion<int>();
|
|
b.Property(x => x.VoiceFilePath).HasMaxLength(500);
|
|
b.HasOne(x => x.Device)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.DeviceId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
b.HasOne(x => x.AuthorUser)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.AuthorUserId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
b.HasIndex(x => new { x.DeviceId, x.CreatedAt });
|
|
b.HasIndex(x => x.AuthorUserId);
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.DevicePostImage>(b =>
|
|
{
|
|
b.ToTable("DevicePostImages");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.FileName).IsRequired().HasMaxLength(255);
|
|
b.Property(x => x.FilePath).IsRequired().HasMaxLength(500);
|
|
b.Property(x => x.ContentType).IsRequired().HasMaxLength(100);
|
|
b.HasOne(x => x.DevicePost)
|
|
.WithMany(p => p.Images)
|
|
.HasForeignKey(x => x.DevicePostId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
b.HasIndex(x => x.DevicePostId);
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.PowerOutageLog>(b =>
|
|
{
|
|
b.ToTable("PowerOutageLogs");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.PreviousPower).IsRequired();
|
|
b.Property(x => x.CurrentPower).IsRequired();
|
|
b.Property(x => x.EventType).IsRequired().HasConversion<int>();
|
|
b.Property(x => x.PersianDate).HasMaxLength(10);
|
|
b.HasOne(x => x.Device)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.DeviceId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
b.HasIndex(x => new { x.DeviceId, x.TimestampUtc });
|
|
b.HasIndex(x => new { x.DeviceId, x.PersianYear, x.PersianMonth });
|
|
b.HasIndex(x => x.EventType);
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.UsageCounter>(b =>
|
|
{
|
|
b.ToTable("UsageCounters");
|
|
b.HasKey(x => x.Id);
|
|
b.HasOne(x => x.User)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.UserId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
b.HasIndex(x => new { x.UserId, x.Date }).IsUnique();
|
|
b.HasIndex(x => x.Date);
|
|
});
|
|
|
|
modelBuilder.Entity<Domain.AdminAuditLog>(b =>
|
|
{
|
|
b.ToTable("AdminAuditLogs");
|
|
b.HasKey(x => x.Id);
|
|
b.Property(x => x.Action).IsRequired().HasMaxLength(100);
|
|
b.Property(x => x.TargetId).IsRequired().HasMaxLength(100);
|
|
b.Property(x => x.Details).HasMaxLength(2000);
|
|
b.HasOne(x => x.AdminUser)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.AdminUserId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
b.HasIndex(x => x.At);
|
|
b.HasIndex(x => x.AdminUserId);
|
|
});
|
|
|
|
// Postgres-specific mappings (SQL Server path is untouched).
|
|
// MUST run last: fluent HasMaxLength/HasColumnType calls above set the
|
|
// values we adjust here, so this block has to see the final model state.
|
|
// 1) DateTime -> "timestamp" (no tz): mirrors naive datetime2, accepts any Kind.
|
|
// 2) varchar: Postgres counts BYTES, SQL Server's nvarchar counts CHARACTERS.
|
|
// x4 keeps char-count semantics for any UTF-8 charset (Persian = 2 bytes/char).
|
|
if (Database.ProviderName == "Npgsql.EntityFrameworkCore.PostgreSQL")
|
|
{
|
|
foreach (var et in modelBuilder.Model.GetEntityTypes())
|
|
{
|
|
foreach (var p in et.GetProperties())
|
|
{
|
|
if (p.ClrType == typeof(DateTime) || p.ClrType == typeof(DateTime?))
|
|
p.SetColumnType("timestamp");
|
|
else if (p.ClrType == typeof(string) && p.GetMaxLength() is int len)
|
|
p.SetColumnType($"character varying({len * 4})");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|