diff --git a/Controllers/DataMigrationController.cs b/Controllers/DataMigrationController.cs
new file mode 100644
index 0000000..62f155d
--- /dev/null
+++ b/Controllers/DataMigrationController.cs
@@ -0,0 +1,69 @@
+using Microsoft.AspNetCore.Mvc;
+using ValuationBackend.Data;
+
+namespace ValuationBackend.Controllers
+{
+ [Route("api/[controller]")]
+ [ApiController]
+ public class DataMigrationController : ControllerBase
+ {
+ private readonly AppDbContext _context;
+
+ public DataMigrationController(AppDbContext context)
+ {
+ _context = context;
+ }
+
+ ///
+ /// Populates foreign keys for LM Rental Evidence records based on existing string references
+ ///
+ [HttpPost("populate-lm-rental-evidence-foreign-keys")]
+ public async Task PopulateLMRentalEvidenceForeignKeys()
+ {
+ try
+ {
+ await PopulateForeignKeysMigration.PopulateLMRentalEvidenceForeignKeys(_context);
+ return Ok(new { message = "Foreign keys populated successfully for LM Rental Evidence." });
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, new { error = "Failed to populate foreign keys", details = ex.Message });
+ }
+ }
+
+ ///
+ /// Validates foreign key relationships for LM Rental Evidence
+ ///
+ [HttpGet("validate-lm-rental-evidence-foreign-keys")]
+ public async Task ValidateLMRentalEvidenceForeignKeys()
+ {
+ try
+ {
+ await PopulateForeignKeysMigration.ValidateForeignKeyRelationships(_context);
+ return Ok(new { message = "Foreign key validation completed. Check console output for details." });
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, new { error = "Failed to validate foreign keys", details = ex.Message });
+ }
+ }
+
+ ///
+ /// Runs both population and validation in sequence
+ ///
+ [HttpPost("migrate-lm-rental-evidence")]
+ public async Task MigrateLMRentalEvidence()
+ {
+ try
+ {
+ await PopulateForeignKeysMigration.PopulateLMRentalEvidenceForeignKeys(_context);
+ await PopulateForeignKeysMigration.ValidateForeignKeyRelationships(_context);
+ return Ok(new { message = "LM Rental Evidence migration completed successfully." });
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, new { error = "Failed to migrate LM Rental Evidence", details = ex.Message });
+ }
+ }
+ }
+}
diff --git a/Controllers/LMBuildingRatesController.cs b/Controllers/LMBuildingRatesController.cs
index 597426f..7d03416 100644
--- a/Controllers/LMBuildingRatesController.cs
+++ b/Controllers/LMBuildingRatesController.cs
@@ -81,5 +81,13 @@ public async Task> GetLMBuildingRateByR
return lmBuildingRate;
}
+
+ // GET: api/LMBuildingRates/ByMasterFile/5
+ [HttpGet("ByMasterFile/{masterFileId}")]
+ public async Task>> GetLMBuildingRatesByMasterFileId(int masterFileId)
+ {
+ var buildingRates = await _lmBuildingRatesService.GetByMasterFileIdAsync(masterFileId);
+ return Ok(buildingRates);
+ }
}
}
diff --git a/Controllers/LMPastValuationController.cs b/Controllers/LMPastValuationController.cs
index 5059497..921271e 100644
--- a/Controllers/LMPastValuationController.cs
+++ b/Controllers/LMPastValuationController.cs
@@ -93,5 +93,13 @@ public async Task> GetLMPastValuationBy
return lmPastValuation;
}
+
+ // GET: api/LMPastValuation/ByMasterFile/5
+ [HttpGet("ByMasterFile/{masterFileId}")]
+ public async Task>> GetLMPastValuationsByMasterFileId(int masterFileId)
+ {
+ var pastValuations = await _lmPastValuationService.GetByMasterFileIdAsync(masterFileId);
+ return Ok(pastValuations);
+ }
}
}
diff --git a/Controllers/LMRentalEvidenceController.cs b/Controllers/LMRentalEvidenceController.cs
index ab60c3d..e0aa5b6 100644
--- a/Controllers/LMRentalEvidenceController.cs
+++ b/Controllers/LMRentalEvidenceController.cs
@@ -93,5 +93,29 @@ public async Task> GetLMRentalEvidence
return lmRentalEvidence;
}
+
+ // NEW: GET: api/LMRentalEvidence/ByMasterFile/123
+ [HttpGet("ByMasterFile/{masterFileId}")]
+ public async Task>> GetByMasterFileId(int masterFileId)
+ {
+ var evidences = await _lmRentalEvidenceService.GetByMasterFileIdAsync(masterFileId);
+ return Ok(evidences);
+ }
+
+ // NEW: GET: api/LMRentalEvidence/ByMasterFileRefNo/MF-2024-001
+ [HttpGet("ByMasterFileRefNo/{masterFileRefNo}")]
+ public async Task>> GetByMasterFileRefNo(string masterFileRefNo)
+ {
+ var evidences = await _lmRentalEvidenceService.GetByMasterFileRefNoAsync(masterFileRefNo);
+ return Ok(evidences);
+ }
+
+ // NEW: GET: api/LMRentalEvidence/WithMasterFileData
+ [HttpGet("WithMasterFileData")]
+ public async Task>> GetAllWithMasterFileData()
+ {
+ var evidences = await _lmRentalEvidenceService.GetAllWithMasterFileDataAsync();
+ return Ok(evidences);
+ }
}
}
diff --git a/Controllers/LMSalesEvidenceController.cs b/Controllers/LMSalesEvidenceController.cs
index 3f357e5..db1a456 100644
--- a/Controllers/LMSalesEvidenceController.cs
+++ b/Controllers/LMSalesEvidenceController.cs
@@ -93,5 +93,13 @@ public async Task> GetLMSalesEvidenceBy
return lmSalesEvidence;
}
+
+ // GET: api/LMSalesEvidence/ByMasterFile/5
+ [HttpGet("ByMasterFile/{masterFileId}")]
+ public async Task>> GetLMSalesEvidencesByMasterFileId(int masterFileId)
+ {
+ var salesEvidences = await _lmSalesEvidenceService.GetByMasterFileIdAsync(masterFileId);
+ return Ok(salesEvidences);
+ }
}
}
diff --git a/Data/AppDbContext.cs b/Data/AppDbContext.cs
index a51a7de..768bddf 100644
--- a/Data/AppDbContext.cs
+++ b/Data/AppDbContext.cs
@@ -84,6 +84,51 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
.HasOne(r => r.Asset)
.WithMany()
.HasForeignKey(r => r.AssetId);
+
+ // NEW: Configure LMRentalEvidence relationships
+ modelBuilder.Entity()
+ .HasOne(lm => lm.LandMiscellaneousMasterFile)
+ .WithMany()
+ .HasForeignKey(lm => lm.LandMiscellaneousMasterFileId)
+ .OnDelete(DeleteBehavior.SetNull);
+
+ // NEW: Add index for performance
+ modelBuilder.Entity()
+ .HasIndex(lm => lm.LandMiscellaneousMasterFileId)
+ .HasDatabaseName("IX_LMRentalEvidence_LandMiscellaneousMasterFileId");
+
+ // Configure LMBuildingRates relationships
+ modelBuilder.Entity()
+ .HasOne(lm => lm.LandMiscellaneousMasterFile)
+ .WithMany() // No navigation property on master file side
+ .HasForeignKey(lm => lm.LandMiscellaneousMasterFileId)
+ .OnDelete(DeleteBehavior.SetNull);
+
+ modelBuilder.Entity()
+ .HasIndex(lm => lm.LandMiscellaneousMasterFileId)
+ .HasDatabaseName("IX_LMBuildingRates_LandMiscellaneousMasterFileId");
+
+ // Configure LMPastValuation relationships
+ modelBuilder.Entity()
+ .HasOne(lm => lm.LandMiscellaneousMasterFile)
+ .WithMany() // No navigation property on master file side
+ .HasForeignKey(lm => lm.LandMiscellaneousMasterFileId)
+ .OnDelete(DeleteBehavior.SetNull);
+
+ modelBuilder.Entity()
+ .HasIndex(lm => lm.LandMiscellaneousMasterFileId)
+ .HasDatabaseName("IX_LMPastValuation_LandMiscellaneousMasterFileId");
+
+ // Configure LMSalesEvidence relationships
+ modelBuilder.Entity()
+ .HasOne(lm => lm.LandMiscellaneousMasterFile)
+ .WithMany() // No navigation property on master file side
+ .HasForeignKey(lm => lm.LandMiscellaneousMasterFileId)
+ .OnDelete(DeleteBehavior.SetNull);
+
+ modelBuilder.Entity()
+ .HasIndex(lm => lm.LandMiscellaneousMasterFileId)
+ .HasDatabaseName("IX_LMSalesEvidence_LandMiscellaneousMasterFileId");
}
}
}
diff --git a/Data/DBInitializer.cs b/Data/DBInitializer.cs
index 27c6dfb..2a85663 100644
--- a/Data/DBInitializer.cs
+++ b/Data/DBInitializer.cs
@@ -32,7 +32,7 @@ public static void Initialize(AppDbContext context)
// Update UserTasks with correct User IDs
UpdateUserTaskUserIds(context);
- // Remove UserTasks that are not LM (Land Miscellaneous)
+ // Remove UserTasks that are not LM (Land Miscellaneous) - COMMENTED OUT to keep LA and MR tasks
// RemoveNonLMUserTasks(context);
// Initialize Master Data
@@ -1137,18 +1137,31 @@ string division
private static void InitializeUserTasks(AppDbContext context)
{
- // Calculate expected task count: 12 LA tasks + number of LM records
- var expectedTaskCount = 12 + context.LandMiscellaneousMasterFiles.Count();
+ // Calculate expected task count: 12 LA/MR tasks + number of LM records
+ var expectedLmTaskCount = context.LandMiscellaneousMasterFiles.Count();
+ var expectedNonLmTaskCount = 12;
+ var currentLmTaskCount = context.UserTasks.Count(t => t.TaskType == "LM");
+ var currentNonLmTaskCount = context.UserTasks.Count(t => t.TaskType != "LM");
- // Check if we already have enough tasks
- if (context.UserTasks.Count() >= expectedTaskCount)
+ // Check if we have sufficient LM tasks - only reseed LM tasks if needed
+ bool needLmTasks = currentLmTaskCount < expectedLmTaskCount;
+ bool needNonLmTasks = currentNonLmTaskCount < expectedNonLmTaskCount;
+
+ if (!needLmTasks && !needNonLmTasks)
return;
- // Remove all existing user tasks to ensure clean seeding
- if (context.UserTasks.Any())
+ // Only remove non-LM tasks if we need to reseed them
+ if (needNonLmTasks && currentNonLmTaskCount > 0)
{
- context.UserTasks.RemoveRange(context.UserTasks);
+ var nonLmTasks = context.UserTasks.Where(t => t.TaskType != "LM").ToList();
+ Console.WriteLine($"Removing {nonLmTasks.Count} UserTask entries with TaskType other than 'LM'...");
+ foreach (var task in nonLmTasks)
+ {
+ Console.WriteLine($"Removing UserTask: Username={task.Username}, TaskType={task.TaskType}, Description={task.WorkItemDescription}");
+ }
+ context.UserTasks.RemoveRange(nonLmTasks);
context.SaveChanges();
+ Console.WriteLine("Non-LM UserTasks removed successfully.");
}
Console.WriteLine("Seeding user tasks...");
@@ -1189,57 +1202,92 @@ void AddTask(string username, string type, bool completed, string date,
);
}
- // Non-LM tasks (LA and MR tasks without referencing old LandMiscellaneous IDs)
- // Jalina's tasks
- AddTask("Jalina", "LA", true, "20250105", landAcquisitionId: 1, description: "Land acquisition survey for Highway Project", referenceNumber: "LA-2025-001");
- AddTask("Jalina", "MR", true, "20250115", requestId: 1, description: "Mass rating assessment - Colombo MC", referenceNumber: "MR-2025-001");
- AddTask("Jalina", "LA", true, "20250301", landAcquisitionId: 2, description: "Land acquisition for Bridge Project", referenceNumber: "LA-2025-002");
-
- // Akith's tasks
- AddTask("Akith", "MR", true, "20250120", requestId: 2, description: "Rating assessment - Galle MC", referenceNumber: "MR-2025-002");
- AddTask("Akith", "LA", false, "20250225", landAcquisitionId: 3, description: "Land acquisition survey", referenceNumber: "LA-2025-003");
-
- // Dulmini's tasks
- AddTask("Dulmini", "LA", true, "20250110", landAcquisitionId: 4, description: "Land acquisition documentation", referenceNumber: "LA-2025-004");
- AddTask("Dulmini", "MR", true, "20250112", requestId: 3, description: "Rating building assessment", referenceNumber: "MR-2025-003");
- AddTask("Dulmini", "MR", false, "20250302", requestId: 1, description: "Follow-up rating assessment", referenceNumber: "MR-2025-004");
-
- // Vishwa's tasks
- AddTask("Vishwa", "LA", true, "20250101", landAcquisitionId: 5, description: "Land acquisition initial survey", referenceNumber: "LA-2025-005");
- AddTask("Vishwa", "LA", true, "20250215", landAcquisitionId: 6, description: "Land acquisition follow-up", referenceNumber: "LA-2025-006");
- AddTask("Vishwa", "MR", true, "20250318", requestId: 2, description: "Additional rating assessment", referenceNumber: "MR-2025-005");
-
- // Rithara's tasks
- AddTask("Rithara", "MR", true, "20250118", requestId: 3, description: "Building rating review", referenceNumber: "MR-2025-006");
- AddTask("Rithara", "LA", false, "20250311", landAcquisitionId: 7, description: "Land acquisition assessment", referenceNumber: "LA-2025-007");
-
- // LM tasks for all current land miscellaneous records - randomly distributed
- var users = new[] { "Jalina", "Akith", "Dulmini", "Vishwa", "Rithara" };
- var planTypes = new[] { "PP", "Cadaster", "FVP" };
- var random = new Random(42); // Fixed seed for consistent results
-
- // Get all actual LandMiscellaneous records from database to use their real IDs
- var landMiscRecords = context.LandMiscellaneousMasterFiles.OrderBy(lm => lm.MasterFileNo).ToList();
+ // Add non-LM tasks only if needed
+ if (needNonLmTasks)
+ {
+ // Non-LM tasks (LA and MR tasks without referencing old LandMiscellaneous IDs)
+ // Jalina's tasks
+ AddTask("Jalina", "LA", true, "20250105", landAcquisitionId: 1, description: "Land acquisition survey for Highway Project", referenceNumber: "LA-2025-001");
+ AddTask("Jalina", "MR", true, "20250115", requestId: 1, description: "Mass rating assessment - Colombo MC", referenceNumber: "MR-2025-001");
+ AddTask("Jalina", "LA", true, "20250301", landAcquisitionId: 2, description: "Land acquisition for Bridge Project", referenceNumber: "LA-2025-002");
+
+ // Akith's tasks
+ AddTask("Akith", "MR", true, "20250120", requestId: 2, description: "Rating assessment - Galle MC", referenceNumber: "MR-2025-002");
+ AddTask("Akith", "LA", false, "20250225", landAcquisitionId: 3, description: "Land acquisition survey", referenceNumber: "LA-2025-003");
+
+ // Dulmini's tasks
+ AddTask("Dulmini", "LA", true, "20250110", landAcquisitionId: 4, description: "Land acquisition documentation", referenceNumber: "LA-2025-004");
+ AddTask("Dulmini", "MR", true, "20250112", requestId: 3, description: "Rating building assessment", referenceNumber: "MR-2025-003");
+ AddTask("Dulmini", "MR", false, "20250302", requestId: 1, description: "Follow-up rating assessment", referenceNumber: "MR-2025-004");
+
+ // Vishwa's tasks
+ AddTask("Vishwa", "LA", true, "20250101", landAcquisitionId: 5, description: "Land acquisition initial survey", referenceNumber: "LA-2025-005");
+ AddTask("Vishwa", "LA", true, "20250215", landAcquisitionId: 6, description: "Land acquisition follow-up", referenceNumber: "LA-2025-006");
+ AddTask("Vishwa", "MR", true, "20250318", requestId: 2, description: "Additional rating assessment", referenceNumber: "MR-2025-005");
+
+ // Rithara's tasks
+ AddTask("Rithara", "MR", true, "20250118", requestId: 3, description: "Building rating review", referenceNumber: "MR-2025-006");
+ AddTask("Rithara", "LA", false, "20250311", landAcquisitionId: 7, description: "Land acquisition assessment", referenceNumber: "LA-2025-007");
+
+ // Additional LA tasks for remaining Land Acquisition Master Files (IDs 8-22)
+ // Distribute among all 5 users
+ AddTask("Jalina", "LA", true, "20250315", landAcquisitionId: 8, description: "Land acquisition survey for Metro Line", referenceNumber: "LA-2025-008");
+ AddTask("Akith", "LA", false, "20250320", landAcquisitionId: 9, description: "Land acquisition for School Development", referenceNumber: "LA-2025-009");
+ AddTask("Dulmini", "LA", true, "20250325", landAcquisitionId: 10, description: "Land acquisition documentation review", referenceNumber: "LA-2025-010");
+ AddTask("Vishwa", "LA", false, "20250330", landAcquisitionId: 11, description: "Land acquisition field verification", referenceNumber: "LA-2025-011");
+ AddTask("Rithara", "LA", true, "20250405", landAcquisitionId: 12, description: "Land acquisition boundary survey", referenceNumber: "LA-2025-012");
+
+ AddTask("Jalina", "LA", false, "20250410", landAcquisitionId: 13, description: "Land acquisition for Hospital Extension", referenceNumber: "LA-2025-013");
+ AddTask("Akith", "LA", true, "20250415", landAcquisitionId: 14, description: "Land acquisition compensation assessment", referenceNumber: "LA-2025-014");
+ AddTask("Dulmini", "LA", false, "20250420", landAcquisitionId: 15, description: "Land acquisition legal documentation", referenceNumber: "LA-2025-015");
+ AddTask("Vishwa", "LA", true, "20250425", landAcquisitionId: 16, description: "Land acquisition site inspection", referenceNumber: "LA-2025-016");
+ AddTask("Rithara", "LA", false, "20250430", landAcquisitionId: 17, description: "Land acquisition valuation report", referenceNumber: "LA-2025-017");
+
+ AddTask("Jalina", "LA", true, "20250505", landAcquisitionId: 18, description: "Land acquisition for Road Widening", referenceNumber: "LA-2025-018");
+ AddTask("Akith", "LA", false, "20250510", landAcquisitionId: 19, description: "Land acquisition preliminary survey", referenceNumber: "LA-2025-019");
+ AddTask("Dulmini", "LA", true, "20250515", landAcquisitionId: 20, description: "Land acquisition title verification", referenceNumber: "LA-2025-020");
+ AddTask("Vishwa", "LA", false, "20250520", landAcquisitionId: 21, description: "Land acquisition environmental assessment", referenceNumber: "LA-2025-021");
+ AddTask("Rithara", "LA", true, "20250525", landAcquisitionId: 22, description: "Land acquisition final documentation", referenceNumber: "LA-2025-022");
+ }
- // Create tasks for each actual LandMiscellaneous record
- for (int i = 0; i < landMiscRecords.Count; i++)
+ // Add LM tasks only if needed
+ if (needLmTasks)
{
- var record = landMiscRecords[i];
- var randomUser = users[random.Next(users.Length)];
- var randomPlanType = planTypes[random.Next(planTypes.Length)];
- var isCompleted = random.Next(100) < 30; // 30% chance of being completed
- var randomDays = random.Next(1, 120); // Random date within last 120 days
- var assignedDate = DateTime.Today.AddDays(-randomDays).ToString("yyyyMMdd");
-
- AddTask(randomUser, "LM", isCompleted, assignedDate,
- landMiscellaneousId: record.Id, // Use the actual database ID
- description: $"{randomPlanType} plan verification for {record.MasterFileNo}",
- referenceNumber: $"LM-2025-{(i + 1):D3}");
+ // LM tasks for all current land miscellaneous records - randomly distributed
+ var users = new[] { "Jalina", "Akith", "Dulmini", "Vishwa", "Rithara" };
+ var planTypes = new[] { "PP", "Cadaster", "FVP" };
+ var random = new Random(42); // Fixed seed for consistent results
+
+ // Get all actual LandMiscellaneous records from database to use their real IDs
+ var landMiscRecords = context.LandMiscellaneousMasterFiles.OrderBy(lm => lm.MasterFileNo).ToList();
+
+ // Create tasks for each actual LandMiscellaneous record
+ for (int i = 0; i < landMiscRecords.Count; i++)
+ {
+ var record = landMiscRecords[i];
+ var randomUser = users[random.Next(users.Length)];
+ var randomPlanType = planTypes[random.Next(planTypes.Length)];
+ var isCompleted = random.Next(100) < 30; // 30% chance of being completed
+ var randomDays = random.Next(1, 120); // Random date within last 120 days
+ var assignedDate = DateTime.Today.AddDays(-randomDays).ToString("yyyyMMdd");
+
+ AddTask(randomUser, "LM", isCompleted, assignedDate,
+ landMiscellaneousId: record.Id, // Use the actual database ID
+ description: $"{randomPlanType} plan verification for {record.MasterFileNo}",
+ referenceNumber: $"LM-2025-{(i + 1):D3}");
+ }
}
- context.UserTasks.AddRange(tasks);
- context.SaveChanges();
- Console.WriteLine("User tasks seeded.");
+ if (tasks.Any())
+ {
+ context.UserTasks.AddRange(tasks);
+ context.SaveChanges();
+ Console.WriteLine($"User tasks seeded. Added {tasks.Count} tasks (LM: {tasks.Count(t => t.TaskType == "LM")}, Non-LM: {tasks.Count(t => t.TaskType != "LM")}).");
+ }
+ else
+ {
+ Console.WriteLine("No new tasks needed - all UserTasks are already properly seeded.");
+ }
}
private static void UpdateUserTaskAssignments(AppDbContext context)
@@ -1484,12 +1532,9 @@ private static void InitializeRequestTypes(AppDbContext context)
private static void InitializeRequests(AppDbContext context)
{
- // Clear existing data to allow reseeding
+ // Only seed if no requests exist
if (context.Requests.Any())
- {
- context.Requests.RemoveRange(context.Requests);
- context.SaveChanges();
- }
+ return;
Console.WriteLine("Seeding requests...");
@@ -1665,12 +1710,9 @@ private static void InitializeRequests(AppDbContext context)
private static void InitializeAssets(AppDbContext context)
{
- // Clear existing data to allow reseeding
+ // Only seed if no assets exist
if (context.Assets.Any())
- {
- context.Assets.RemoveRange(context.Assets);
- context.SaveChanges();
- }
+ return;
Console.WriteLine("Seeding assets...");
diff --git a/Data/PopulateForeignKeysMigration.cs b/Data/PopulateForeignKeysMigration.cs
new file mode 100644
index 0000000..a722272
--- /dev/null
+++ b/Data/PopulateForeignKeysMigration.cs
@@ -0,0 +1,99 @@
+using Microsoft.EntityFrameworkCore;
+using ValuationBackend.Models;
+
+namespace ValuationBackend.Data
+{
+ public static class PopulateForeignKeysMigration
+ {
+ ///
+ /// Populates the LandMiscellaneousMasterFileId foreign key in LMRentalEvidence
+ /// based on existing MasterFileRefNo values
+ ///
+ public static async Task PopulateLMRentalEvidenceForeignKeys(AppDbContext context)
+ {
+ // Get all rental evidences where foreign key is null but string reference exists
+ var rentalEvidences = await context.LMRentalEvidences
+ .Where(re => re.LandMiscellaneousMasterFileId == null &&
+ !string.IsNullOrEmpty(re.MasterFileRefNo))
+ .ToListAsync();
+
+ if (!rentalEvidences.Any())
+ {
+ Console.WriteLine("No rental evidences found that need foreign key population.");
+ return;
+ }
+
+ Console.WriteLine($"Found {rentalEvidences.Count} rental evidences to update.");
+
+ int updatedCount = 0;
+ int skippedCount = 0;
+
+ foreach (var evidence in rentalEvidences)
+ {
+ // Find the corresponding master file
+ var masterFile = await context.LandMiscellaneousMasterFiles
+ .FirstOrDefaultAsync(mf => mf.MasterFileRefNo == evidence.MasterFileRefNo);
+
+ if (masterFile != null)
+ {
+ evidence.LandMiscellaneousMasterFileId = masterFile.Id;
+ updatedCount++;
+ Console.WriteLine($"Updated rental evidence ID {evidence.Id} with master file ID {masterFile.Id}");
+ }
+ else
+ {
+ skippedCount++;
+ Console.WriteLine($"Warning: No master file found for reference number '{evidence.MasterFileRefNo}' (Rental Evidence ID: {evidence.Id})");
+ }
+ }
+
+ if (updatedCount > 0)
+ {
+ await context.SaveChangesAsync();
+ Console.WriteLine($"Successfully updated {updatedCount} rental evidence records.");
+ }
+
+ if (skippedCount > 0)
+ {
+ Console.WriteLine($"Skipped {skippedCount} records due to missing master file references.");
+ }
+ }
+
+ ///
+ /// Validates the foreign key relationships after population
+ ///
+ public static async Task ValidateForeignKeyRelationships(AppDbContext context)
+ {
+ // Check for rental evidences with valid foreign keys
+ var withForeignKeys = await context.LMRentalEvidences
+ .CountAsync(re => re.LandMiscellaneousMasterFileId.HasValue);
+
+ // Check for rental evidences without foreign keys but with string references
+ var withoutForeignKeys = await context.LMRentalEvidences
+ .CountAsync(re => !re.LandMiscellaneousMasterFileId.HasValue &&
+ !string.IsNullOrEmpty(re.MasterFileRefNo));
+
+ // Check for orphaned references (string references that don't match any master file)
+ var orphanedReferences = await context.LMRentalEvidences
+ .Where(re => !string.IsNullOrEmpty(re.MasterFileRefNo))
+ .Where(re => !context.LandMiscellaneousMasterFiles
+ .Any(mf => mf.MasterFileRefNo == re.MasterFileRefNo))
+ .CountAsync();
+
+ Console.WriteLine("=== Foreign Key Relationship Validation ===");
+ Console.WriteLine($"Rental evidences with foreign keys: {withForeignKeys}");
+ Console.WriteLine($"Rental evidences without foreign keys (but with string refs): {withoutForeignKeys}");
+ Console.WriteLine($"Orphaned string references: {orphanedReferences}");
+
+ if (withoutForeignKeys > 0)
+ {
+ Console.WriteLine("Warning: Some rental evidences still lack foreign key relationships.");
+ }
+
+ if (orphanedReferences > 0)
+ {
+ Console.WriteLine("Warning: Some rental evidences reference master files that don't exist.");
+ }
+ }
+ }
+}
diff --git a/Extensions/ServiceExtensions.cs b/Extensions/ServiceExtensions.cs
index 1fcf6d3..3fdccd8 100644
--- a/Extensions/ServiceExtensions.cs
+++ b/Extensions/ServiceExtensions.cs
@@ -15,6 +15,7 @@ public static IServiceCollection AddServices(this IServiceCollection services)
services.AddScoped();
services.AddScoped();
services.AddScoped();
+ services.AddScoped();
services.AddScoped();
services.AddScoped();
services.AddScoped();
diff --git a/Migrations/20250720064824_AddMasterFileRefNoToLandMiscellaneousMasterFile.Designer.cs b/Migrations/20250720064824_AddMasterFileRefNoToLandMiscellaneousMasterFile.Designer.cs
new file mode 100644
index 0000000..608699d
--- /dev/null
+++ b/Migrations/20250720064824_AddMasterFileRefNoToLandMiscellaneousMasterFile.Designer.cs
@@ -0,0 +1,1714 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using ValuationBackend.Data;
+
+#nullable disable
+
+namespace ValuationBackend.Migrations
+{
+ [DbContext(typeof(AppDbContext))]
+ [Migration("20250720064824_AddMasterFileRefNoToLandMiscellaneousMasterFile")]
+ partial class AddMasterFileRefNoToLandMiscellaneousMasterFile
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.5")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("LandAquisitionMasterFile", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("MasterFileNo")
+ .HasColumnType("integer");
+
+ b.Property("MasterFilesRefNo")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("PlanNo")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("PlanType")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("RequestingAuthorityReferenceNo")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("LandAquisitionMasterFiles");
+ });
+
+ modelBuilder.Entity("ValuationBackend.Models.Asset", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AssetNo")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Description")
+ .HasColumnType("integer");
+
+ b.Property("IsRatingCard")
+ .HasColumnType("boolean");
+
+ b.Property("Owner")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("character varying(200)");
+
+ b.Property("RdSt")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("character varying(200)");
+
+ b.Property("RequestId")
+ .HasColumnType("integer");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Ward")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("character varying(200)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("RequestId");
+
+ b.ToTable("Assets");
+ });
+
+ modelBuilder.Entity("ValuationBackend.Models.AssetDivision", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Area")
+ .HasColumnType("numeric");
+
+ b.Property("AssetId")
+ .HasColumnType("integer");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Description")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("character varying(500)");
+
+ b.Property("LandType")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)");
+
+ b.Property("NewAssetNo")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AssetId");
+
+ b.ToTable("AssetDivisions");
+ });
+
+ modelBuilder.Entity("ValuationBackend.Models.AssetNumberChange", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ChangedDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateOfChange")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Description")
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("FieldSize")
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("FieldType")
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("NewAssetNo")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("OldAssetNo")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("Reason")
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)");
+
+ b.HasKey("Id");
+
+ b.ToTable("AssetNumberChanges");
+ });
+
+ modelBuilder.Entity("ValuationBackend.Models.BuildingRatesLA", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AssessmentNumber")
+ .HasColumnType("text");
+
+ b.Property("ConstructedBy")
+ .HasColumnType("text");
+
+ b.Property("Cost")
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DescriptionOfProperty")
+ .HasColumnType("text");
+
+ b.Property("FloorAreaSQFT")
+ .HasColumnType("text");
+
+ b.Property("LocationLatitude")
+ .HasColumnType("text");
+
+ b.Property("LocationLongitude")
+ .HasColumnType("text");
+
+ b.Property("MasterFileId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Owner")
+ .HasColumnType("text");
+
+ b.Property("RatePerSQFT")
+ .HasColumnType("text");
+
+ b.Property("Remarks")
+ .HasColumnType("text");
+
+ b.Property("ReportId")
+ .HasColumnType("integer");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("YearOfConstruction")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ReportId");
+
+ b.ToTable("BuildingRatesLA");
+ });
+
+ modelBuilder.Entity("ValuationBackend.Models.ConditionReport", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AccessCategory")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("AccessCategoryDescription")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("AcquiredExtent")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("AcquiringOfficerSignature")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("AcquisitionName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("AssessmentNumber")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("AtLotNumber")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("AtPlanNumber")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("BoundaryBottom")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("BoundaryEast")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("BoundaryNorth")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("BoundarySouth")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("BoundaryWest")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("BuildingDescription")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("BuildingInfo")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ChiefValuerRepresentativeSignature")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateOfSection3BA")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("DatePrepared")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("DepthOfLand")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("DescriptionOfLand")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("DetailsOfBusiness")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Frontage")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("GramasewakaSignature")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("LandUseDescription")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("LandUseType")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("LevelWithAccess")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("MasterFileId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("NameOfTheLand")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("NameOfTheVillage")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("OtherConstructionsDescription")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("OtherConstructionsInfo")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("PlantationDetails")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("PpCadLotNumber")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("PpCadNumber")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ReportId")
+ .HasColumnType("integer");
+
+ b.Property("RoadName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ReportId");
+
+ b.ToTable("ConditionReports");
+ });
+
+ modelBuilder.Entity("ValuationBackend.Models.DomesticRatingCard", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Access")
+ .HasColumnType("text");
+
+ b.Property("Age")
+ .HasColumnType("integer");
+
+ b.Property("AssetId")
+ .HasColumnType("integer");
+
+ b.Property("Condition")
+ .HasColumnType("text");
+
+ b.Property("Conveniences")
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Date")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Description")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Floor")
+ .HasColumnType("text");
+
+ b.Property("NewNumber")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Notes")
+ .HasColumnType("text");
+
+ b.Property("Occupier")
+ .HasColumnType("text");
+
+ b.Property("Owner")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ParkingSpace")
+ .HasColumnType("text");
+
+ b.Property("Plantations")
+ .HasColumnType("text");
+
+ b.Property("PropertySubCategory")
+ .HasColumnType("text");
+
+ b.Property("PropertyType")
+ .HasColumnType("text");
+
+ b.Property("RentPM")
+ .HasColumnType("numeric");
+
+ b.Property("RoadName")
+ .HasColumnType("text");
+
+ b.Property("SelectWalls")
+ .HasColumnType("text");
+
+ b.Property("SuggestedRate")
+ .HasColumnType("numeric");
+
+ b.Property("Terms")
+ .HasColumnType("text");
+
+ b.Property("TsBop")
+ .HasColumnType("text");
+
+ b.Property("WardNumber")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AssetId");
+
+ b.ToTable("DomesticRatingCards");
+ });
+
+ modelBuilder.Entity("ValuationBackend.Models.ImageData", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ImageBase64")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ReportId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("ImageData");
+ });
+
+ modelBuilder.Entity("ValuationBackend.Models.InspectionBuilding", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AgeYears")
+ .HasColumnType("text");
+
+ b.Property("BathroomToilet")
+ .HasColumnType("text");
+
+ b.Property("BathroomToiletDoorsFittings")
+ .HasColumnType("text");
+
+ b.Property("BuildingCategory")
+ .HasColumnType("text");
+
+ b.Property("BuildingClass")
+ .HasColumnType("text");
+
+ b.Property("BuildingConditions")
+ .HasColumnType("text");
+
+ b.Property("BuildingId")
+ .HasColumnType("text");
+
+ b.Property("BuildingName")
+ .HasColumnType("text");
+
+ b.Property("Ceiling")
+ .HasColumnType("text");
+
+ b.Property("Condition")
+ .HasColumnType("text");
+
+ b.Property("Conveniences")
+ .HasColumnType("text");
+
+ b.Property("Design")
+ .HasColumnType("text");
+
+ b.Property("DetailOfBuilding")
+ .HasColumnType("text");
+
+ b.Property("Door")
+ .HasColumnType("text");
+
+ b.Property("ExpectedLifePeriodYears")
+ .HasColumnType("text");
+
+ b.Property("FloorFinisher")
+ .HasColumnType("text");
+
+ b.Property("FloorStructure")
+ .HasColumnType("text");
+
+ b.Property("FoundationStructure")
+ .HasColumnType("text");
+
+ b.Property("HandRail")
+ .HasColumnType("text");
+
+ b.Property("InspectionReportId")
+ .HasColumnType("integer");
+
+ b.Property("NatureOfConstruction")
+ .HasColumnType("text");
+
+ b.Property("NoOfFloorsAboveGround")
+ .HasColumnType("text")
+ .HasColumnName("NoOfFloorsAboveGround");
+
+ b.Property("NoOfFloorsBelowGround")
+ .HasColumnType("text")
+ .HasColumnName("NoOfFloorsBelowGround");
+
+ b.Property("OtherDoors")
+ .HasColumnType("text");
+
+ b.Property("PantryCupboard")
+ .HasColumnType("text");
+
+ b.Property("ParkingSpace")
+ .HasColumnType("text");
+
+ b.Property("RoofFinisher")
+ .HasColumnType("text");
+
+ b.Property("RoofFrame")
+ .HasColumnType("text");
+
+ b.Property("RoofMaterial")
+ .HasColumnType("text");
+
+ b.Property("Services")
+ .HasColumnType("text");
+
+ b.Property("Structure")
+ .HasColumnType("text");
+
+ b.Property("WallFinisher")
+ .HasColumnType("text");
+
+ b.Property("WallStructure")
+ .HasColumnType("text");
+
+ b.Property("Window")
+ .HasColumnType("text");
+
+ b.Property("WindowProtection")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InspectionReportId");
+
+ b.ToTable("InspectionBuildings");
+ });
+
+ modelBuilder.Entity("ValuationBackend.Models.InspectionReport", b =>
+ {
+ b.Property("InspectionReportId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("InspectionReportId"));
+
+ b.Property("DetailsOfAssestsInventoryItems")
+ .HasColumnType("text")
+ .HasColumnName("DetailsOfAssestsInventoryItems");
+
+ b.Property("DetailsOfBusiness")
+ .HasColumnType("text");
+
+ b.Property("District")
+ .HasColumnType("text");
+
+ b.Property("DsDivision")
+ .HasColumnType("text");
+
+ b.Property("GnDivision")
+ .HasColumnType("text");
+
+ b.Property("InspectionDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("MasterFileId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("MasterFileRefNo")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("OtherConstructionDetails")
+ .HasColumnType("text");
+
+ b.Property("OtherInformation")
+ .HasColumnType("text");
+
+ b.Property("Province")
+ .HasColumnType("text");
+
+ b.Property("Remark")
+ .HasColumnType("text");
+
+ b.Property("ReportId")
+ .HasColumnType("integer");
+
+ b.Property("Village")
+ .HasColumnType("text");
+
+ b.HasKey("InspectionReportId");
+
+ b.HasIndex("ReportId");
+
+ b.ToTable("InspectionReports");
+ });
+
+ modelBuilder.Entity("ValuationBackend.Models.LMBuildingRates", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AssessmentNumber")
+ .HasColumnType("text");
+
+ b.Property("ConstructedBy")
+ .HasColumnType("text");
+
+ b.Property("Cost")
+ .HasColumnType("text");
+
+ b.Property("DescriptionOfProperty")
+ .HasColumnType("text");
+
+ b.Property("FloorArea")
+ .HasColumnType("text");
+
+ b.Property("LocationLatitude")
+ .HasColumnType("text");
+
+ b.Property("LocationLongitude")
+ .HasColumnType("text");
+
+ b.Property("MasterFileRefNo")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Owner")
+ .HasColumnType("text");
+
+ b.Property("RatePerSQFT")
+ .HasColumnType("text");
+
+ b.Property("Remarks")
+ .HasColumnType("text");
+
+ b.Property("ReportId")
+ .HasColumnType("integer");
+
+ b.Property("YearOfConstruction")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ReportId");
+
+ b.ToTable("LMBuildingRates");
+ });
+
+ modelBuilder.Entity("ValuationBackend.Models.LMPastValuation", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("DateOfValuation")
+ .HasColumnType("text");
+
+ b.Property("Extent")
+ .HasColumnType("text");
+
+ b.Property("FileNo_GnDivision")
+ .HasColumnType("text");
+
+ b.Property("LocationLatitude")
+ .HasColumnType("text");
+
+ b.Property("LocationLongitude")
+ .HasColumnType("text");
+
+ b.Property("MasterFileRefNo")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("PlanOfParticulars")
+ .HasColumnType("text");
+
+ b.Property("PurposeOfValuation")
+ .HasColumnType("text");
+
+ b.Property("Rate")
+ .HasColumnType("text");
+
+ b.Property("RateType")
+ .HasColumnType("text");
+
+ b.Property("Remarks")
+ .HasColumnType("text");
+
+ b.Property("ReportId")
+ .HasColumnType("integer");
+
+ b.Property("Situation")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ReportId");
+
+ b.ToTable("LMPastValuations");
+ });
+
+ modelBuilder.Entity("ValuationBackend.Models.LMRentalEvidence", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AssessmentNo")
+ .HasColumnType("text");
+
+ b.Property("Description")
+ .HasColumnType("text");
+
+ b.Property("FloorRate")
+ .HasColumnType("text");
+
+ b.Property("HeadOfTerms")
+ .HasColumnType("text");
+
+ b.Property("LocationLatitude")
+ .HasColumnType("text");
+
+ b.Property("LocationLongitude")
+ .HasColumnType("text");
+
+ b.Property("MasterFileRefNo")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Occupier")
+ .HasColumnType("text");
+
+ b.Property("Owner")
+ .HasColumnType("text");
+
+ b.Property("RatePer")
+ .HasColumnType("text");
+
+ b.Property("RatePerMonth")
+ .HasColumnType("text");
+
+ b.Property("Remarks")
+ .HasColumnType("text");
+
+ b.Property("ReportId")
+ .HasColumnType("integer");
+
+ b.Property("Situation")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ReportId");
+
+ b.ToTable("LMRentalEvidences");
+ });
+
+ modelBuilder.Entity("ValuationBackend.Models.LMSalesEvidence", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AssetNumber")
+ .HasColumnType("text");
+
+ b.Property("Consideration")
+ .HasColumnType("text");
+
+ b.Property