ProjectDetails_Split_API #103

Merged
admin merged 47 commits from ProjectDetails_Split_API into main 2025-07-11 11:32:34 +00:00
8 changed files with 144 additions and 66 deletions
Showing only changes of commit 1d318c75d8 - Show all commits

View File

@ -22,31 +22,47 @@ namespace Marco.Pms.CacheHelper
}
public async Task<bool> AddApplicationRoleToCache(Guid employeeId, List<Guid> roleIds)
{
var newRoleIds = roleIds.Select(r => r.ToString()).ToList();
var newPermissionIds = await _context.RolePermissionMappings
// 1. Guard Clause: Avoid unnecessary database work if there are no roles to add.
if (roleIds == null || !roleIds.Any())
{
return false; // Nothing to add, so the operation did not result in a change.
}
// 2. Perform database queries concurrently for better performance.
var employeeIdString = employeeId.ToString();
Task<List<string>> getPermissionIdsTask = _context.RolePermissionMappings
.Where(rp => roleIds.Contains(rp.ApplicationRoleId))
.Select(p => p.FeaturePermissionId.ToString())
.Distinct()
.ToListAsync();
var filter = Builders<EmployeePermissionMongoDB>.Filter.Eq(e => e.EmployeeId, employeeId.ToString());
// 3. Prepare role IDs in parallel with the database query.
var newRoleIds = roleIds.Select(r => r.ToString()).ToList();
// 4. Await the database query result.
var newPermissionIds = await getPermissionIdsTask;
// 5. Build a single, efficient update operation.
var filter = Builders<EmployeePermissionMongoDB>.Filter.Eq(e => e.Id, employeeIdString);
var update = Builders<EmployeePermissionMongoDB>.Update
.AddToSetEach(e => e.ApplicationRoleIds, newRoleIds)
.AddToSetEach(e => e.PermissionIds, newPermissionIds);
var result = await _collection.UpdateOneAsync(filter, update, new UpdateOptions { IsUpsert = true });
if (result.MatchedCount == 0)
{
return false;
}
return true;
var options = new UpdateOptions { IsUpsert = true };
var result = await _collection.UpdateOneAsync(filter, update, options);
// 6. Return a more accurate result indicating success for both updates and upserts.
// The operation is successful if an existing document was modified OR a new one was created.
return result.IsAcknowledged && (result.ModifiedCount > 0 || result.UpsertedId != null);
}
public async Task<bool> AddProjectsToCache(Guid employeeId, List<Guid> projectIds)
{
var newprojectIds = projectIds.Select(p => p.ToString()).ToList();
var filter = Builders<EmployeePermissionMongoDB>.Filter.Eq(e => e.EmployeeId, employeeId.ToString());
var filter = Builders<EmployeePermissionMongoDB>.Filter.Eq(e => e.Id, employeeId.ToString());
var update = Builders<EmployeePermissionMongoDB>.Update
.AddToSetEach(e => e.ProjectIds, newprojectIds);
@ -60,7 +76,7 @@ namespace Marco.Pms.CacheHelper
}
public async Task<List<Guid>> GetProjectsFromCache(Guid employeeId)
{
var filter = Builders<EmployeePermissionMongoDB>.Filter.Eq(e => e.EmployeeId, employeeId.ToString());
var filter = Builders<EmployeePermissionMongoDB>.Filter.Eq(e => e.Id, employeeId.ToString());
var result = await _collection
@ -77,7 +93,7 @@ namespace Marco.Pms.CacheHelper
}
public async Task<List<Guid>> GetPermissionsFromCache(Guid employeeId)
{
var filter = Builders<EmployeePermissionMongoDB>.Filter.Eq(e => e.EmployeeId, employeeId.ToString());
var filter = Builders<EmployeePermissionMongoDB>.Filter.Eq(e => e.Id, employeeId.ToString());
var result = await _collection
@ -95,7 +111,21 @@ namespace Marco.Pms.CacheHelper
public async Task<bool> ClearAllProjectIdsFromCache(Guid employeeId)
{
var filter = Builders<EmployeePermissionMongoDB>.Filter
.Eq(e => e.EmployeeId, employeeId.ToString());
.Eq(e => e.Id, employeeId.ToString());
var update = Builders<EmployeePermissionMongoDB>.Update
.Set(e => e.ProjectIds, new List<string>());
var result = await _collection.UpdateOneAsync(filter, update);
if (result.MatchedCount == 0)
return false;
return true;
}
public async Task<bool> ClearAllProjectIdsByRoleIdFromCache(Guid roleId)
{
var filter = Builders<EmployeePermissionMongoDB>.Filter.AnyEq(e => e.ApplicationRoleIds, roleId.ToString());
var update = Builders<EmployeePermissionMongoDB>.Update
.Set(e => e.ProjectIds, new List<string>());
@ -110,7 +140,7 @@ namespace Marco.Pms.CacheHelper
public async Task<bool> RemoveRoleIdFromCache(Guid employeeId, Guid roleId)
{
var filter = Builders<EmployeePermissionMongoDB>.Filter
.Eq(e => e.EmployeeId, employeeId.ToString());
.Eq(e => e.Id, employeeId.ToString());
var update = Builders<EmployeePermissionMongoDB>.Update
.Pull(e => e.ApplicationRoleIds, roleId.ToString());
@ -128,7 +158,7 @@ namespace Marco.Pms.CacheHelper
public async Task<bool> ClearAllPermissionIdsByEmployeeIDFromCache(Guid employeeId)
{
var filter = Builders<EmployeePermissionMongoDB>.Filter
.Eq(e => e.EmployeeId, employeeId.ToString());
.Eq(e => e.Id, employeeId.ToString());
var update = Builders<EmployeePermissionMongoDB>.Update
.Set(e => e.PermissionIds, new List<string>());

View File

@ -11,19 +11,21 @@ namespace Marco.Pms.CacheHelper
public class ProjectCache
{
private readonly ApplicationDbContext _context;
private readonly IMongoDatabase _mongoDB;
//private readonly ILoggingService _logger;
private readonly IMongoCollection<ProjectMongoDB> _projetCollection;
private readonly IMongoCollection<WorkItemMongoDB> _taskCollection;
public ProjectCache(ApplicationDbContext context, IConfiguration configuration)
{
var connectionString = configuration["MongoDB:ConnectionString"];
_context = context;
var mongoUrl = new MongoUrl(connectionString);
var client = new MongoClient(mongoUrl); // Your MongoDB connection string
_mongoDB = client.GetDatabase(mongoUrl.DatabaseName); // Your MongoDB Database name
var mongoDB = client.GetDatabase(mongoUrl.DatabaseName); // Your MongoDB Database name
_projetCollection = mongoDB.GetCollection<ProjectMongoDB>("ProjectDetails");
_taskCollection = mongoDB.GetCollection<WorkItemMongoDB>("WorkItemDetails");
}
public async Task AddProjectDetailsToCache(Project project)
{
var projectCollection = _mongoDB.GetCollection<ProjectMongoDB>("ProjectDetails");
//_logger.LogInfo("[AddProjectDetails] Initiated for ProjectId: {ProjectId}", project.Id);
@ -145,7 +147,7 @@ namespace Marco.Pms.CacheHelper
projectDetails.PlannedWork = totalPlannedWork;
projectDetails.CompletedWork = totalCompletedWork;
await projectCollection.InsertOneAsync(projectDetails);
await _projetCollection.InsertOneAsync(projectDetails);
//_logger.LogInfo("[AddProjectDetails] Project details inserted in MongoDB for ProjectId: {ProjectId}", project.Id);
}
public async Task<bool> UpdateProjectDetailsOnlyToCache(Project project)
@ -160,8 +162,6 @@ namespace Marco.Pms.CacheHelper
//_logger.LogWarning("StatusMaster not found for ProjectStatusId: {StatusId}", project.ProjectStatusId);
}
var projectCollection = _mongoDB.GetCollection<ProjectMongoDB>("ProjectDetails");
// Build the update definition
var updates = Builders<ProjectMongoDB>.Update.Combine(
Builders<ProjectMongoDB>.Update.Set(r => r.Name, project.Name),
@ -178,7 +178,7 @@ namespace Marco.Pms.CacheHelper
);
// Perform the update
var result = await projectCollection.UpdateOneAsync(
var result = await _projetCollection.UpdateOneAsync(
filter: r => r.Id == project.Id.ToString(),
update: updates
);
@ -194,7 +194,6 @@ namespace Marco.Pms.CacheHelper
}
public async Task<ProjectMongoDB?> GetProjectDetailsFromCache(Guid projectId)
{
var projectCollection = _mongoDB.GetCollection<ProjectMongoDB>("ProjectDetails");
// Build filter and projection to exclude large 'Buildings' list
var filter = Builders<ProjectMongoDB>.Filter.Eq(p => p.Id, projectId.ToString());
@ -203,7 +202,7 @@ namespace Marco.Pms.CacheHelper
//_logger.LogInfo("Fetching project details for ProjectId: {ProjectId} from MongoDB", projectId);
// Perform query
var project = await projectCollection
var project = await _projetCollection
.Find(filter)
.Project<ProjectMongoDB>(projection)
.FirstOrDefaultAsync();
@ -214,16 +213,23 @@ namespace Marco.Pms.CacheHelper
return null;
}
//// Deserialize the result manually
//var project = BsonSerializer.Deserialize<ProjectMongoDB>(result);
//_logger.LogInfo("Successfully fetched project details (excluding Buildings) for ProjectId: {ProjectId}", projectId);
return project;
}
public async Task<List<ProjectMongoDB>?> GetProjectDetailsListFromCache(List<Guid> projectIds)
{
List<string> stringProjectIds = projectIds.Select(p => p.ToString()).ToList();
var filter = Builders<ProjectMongoDB>.Filter.In(p => p.Id, stringProjectIds);
var projection = Builders<ProjectMongoDB>.Projection.Exclude(p => p.Buildings);
var projects = await _projetCollection
.Find(filter)
.Project<ProjectMongoDB>(projection)
.ToListAsync();
return projects;
}
public async Task AddBuildngInfraToCache(Guid projectId, Building? building, Floor? floor, WorkArea? workArea, Guid? buildingId)
{
var stringProjectId = projectId.ToString();
var projectCollection = _mongoDB.GetCollection<ProjectMongoDB>("ProjectDetails");
// Add Building
if (building != null)
@ -241,7 +247,7 @@ namespace Marco.Pms.CacheHelper
var filter = Builders<ProjectMongoDB>.Filter.Eq(p => p.Id, stringProjectId);
var update = Builders<ProjectMongoDB>.Update.Push("Buildings", buildingMongo);
var result = await projectCollection.UpdateOneAsync(filter, update);
var result = await _projetCollection.UpdateOneAsync(filter, update);
if (result.MatchedCount == 0)
{
@ -271,7 +277,7 @@ namespace Marco.Pms.CacheHelper
);
var update = Builders<ProjectMongoDB>.Update.Push("Buildings.$.Floors", floorMongo);
var result = await projectCollection.UpdateOneAsync(filter, update);
var result = await _projetCollection.UpdateOneAsync(filter, update);
if (result.MatchedCount == 0)
{
@ -305,7 +311,7 @@ namespace Marco.Pms.CacheHelper
var update = Builders<ProjectMongoDB>.Update.Push("Buildings.$[b].Floors.$[f].WorkAreas", workAreaMongo);
var updateOptions = new UpdateOptions { ArrayFilters = arrayFilters };
var result = await projectCollection.UpdateOneAsync(filter, update, updateOptions);
var result = await _projetCollection.UpdateOneAsync(filter, update, updateOptions);
if (result.MatchedCount == 0)
{
@ -323,7 +329,6 @@ namespace Marco.Pms.CacheHelper
public async Task<bool> UpdateBuildngInfraToCache(Guid projectId, Building? building, Floor? floor, WorkArea? workArea, Guid? buildingId)
{
var stringProjectId = projectId.ToString();
var projectCollection = _mongoDB.GetCollection<ProjectMongoDB>("ProjectDetails");
// Update Building
if (building != null)
@ -338,7 +343,7 @@ namespace Marco.Pms.CacheHelper
Builders<ProjectMongoDB>.Update.Set("Buildings.$.Description", building.Description)
);
var result = await projectCollection.UpdateOneAsync(filter, update);
var result = await _projetCollection.UpdateOneAsync(filter, update);
if (result.MatchedCount == 0)
{
@ -363,7 +368,7 @@ namespace Marco.Pms.CacheHelper
var updateOptions = new UpdateOptions { ArrayFilters = arrayFilters };
var filter = Builders<ProjectMongoDB>.Filter.Eq(p => p.Id, stringProjectId);
var result = await projectCollection.UpdateOneAsync(filter, update, updateOptions);
var result = await _projetCollection.UpdateOneAsync(filter, update, updateOptions);
if (result.MatchedCount == 0)
{
@ -389,7 +394,7 @@ namespace Marco.Pms.CacheHelper
var updateOptions = new UpdateOptions { ArrayFilters = arrayFilters };
var filter = Builders<ProjectMongoDB>.Filter.Eq(p => p.Id, stringProjectId);
var result = await projectCollection.UpdateOneAsync(filter, update, updateOptions);
var result = await _projetCollection.UpdateOneAsync(filter, update, updateOptions);
if (result.MatchedCount == 0)
{
@ -408,13 +413,12 @@ namespace Marco.Pms.CacheHelper
}
public async Task<List<BuildingMongoDB>?> GetBuildingInfraFromCache(Guid projectId)
{
var projectCollection = _mongoDB.GetCollection<ProjectMongoDB>("ProjectDetails");
// Filter by project ID
var filter = Builders<ProjectMongoDB>.Filter.Eq(p => p.Id, projectId.ToString());
// Project only the "Buildings" field from the document
var buildings = await projectCollection
var buildings = await _projetCollection
.Find(filter)
.Project(p => p.Buildings)
.FirstOrDefaultAsync();
@ -430,5 +434,10 @@ namespace Marco.Pms.CacheHelper
return buildings;
}
// ------------------------------------------------------- WorkItem -------------------------------------------------------
}
}

View File

@ -5,7 +5,7 @@ namespace Marco.Pms.Model.MongoDBModels
[BsonIgnoreExtraElements]
public class EmployeePermissionMongoDB
{
public string EmployeeId { get; set; } = string.Empty;
public string Id { get; set; } = string.Empty; // Employee ID
public List<string> ApplicationRoleIds { get; set; } = new List<string>();
public List<string> PermissionIds { get; set; } = new List<string>();
public List<string> ProjectIds { get; set; } = new List<string>();

View File

@ -2,7 +2,7 @@
{
public class ProjectMongoDB
{
public string? Id { get; set; }
public string Id { get; set; } = string.Empty;
public string? Name { get; set; }
public string? ShortName { get; set; }
public string? ProjectAddress { get; set; }

View File

@ -2,13 +2,14 @@
{
public class WorkItemMongoDB
{
public string? Id { get; set; }
public string? WorkAreaId { get; set; }
public string Id { get; set; } = string.Empty;
public string WorkAreaId { get; set; } = string.Empty;
public ActivityMasterMongoDB? ActivityMaster { get; set; }
public WorkCategoryMasterMongoDB? WorkCategoryMaster { get; set; }
public string? ParentTaskId { get; set; }
public double PlannedWork { get; set; }
public double CompletedWork { get; set; }
public double PlannedWork { get; set; } = 0;
public double TodaysAssigned { get; set; } = 0;
public double CompletedWork { get; set; } = 0;
public string? Description { get; set; }
public DateTime TaskDate { get; set; }
}

View File

@ -292,6 +292,10 @@ namespace MarcoBMS.Services.Controllers
_context.RolePermissionMappings.Add(item);
modified = true;
}
if (item.FeaturePermissionId == Guid.Parse("172fc9b6-755b-4f62-ab26-55c34a330614"))
{
await _cache.ClearAllProjectIdsByRoleId(id);
}
}
if (modified)
await _context.SaveChangesAsync();

View File

@ -28,7 +28,7 @@ namespace Marco.Pms.Services.Helpers
}
catch (Exception ex)
{
_logger.LogWarning("Error occured while adding project to Cache: {Error}", ex.Message);
_logger.LogWarning("Error occured while adding project {ProjectId} to Cache : {Error}", project.Id, ex.Message);
}
}
public async Task<bool> UpdateProjectDetailsOnly(Project project)
@ -40,7 +40,7 @@ namespace Marco.Pms.Services.Helpers
}
catch (Exception ex)
{
_logger.LogWarning("Error occured while updating project to Cache: {Error}", ex.Message);
_logger.LogWarning("Error occured while updating project {ProjectId} to Cache: {Error}", project.Id, ex.Message);
return false;
}
}
@ -53,15 +53,23 @@ namespace Marco.Pms.Services.Helpers
}
catch (Exception ex)
{
_logger.LogWarning("Error occured while getting project to Cache: {Error}", ex.Message);
_logger.LogWarning("Error occured while getting project {ProjectId} to Cache: {Error}", ex.Message);
return null;
}
}
public async Task<List<ProjectMongoDB>?> GetProjectDetailsList(List<Guid> projectIds)
{
try
{
var response = await _projectCache.GetProjectDetailsListFromCache(projectIds);
return response;
}
catch (Exception ex)
{
_logger.LogWarning("Error occured while getting list od project details from to Cache: {Error}", ex.Message);
return null;
}
}
//public async Task<List<ProjectMongoDB>?> GetProjectDetailsList(List<Guid> projectIds)
//{
// var response = await _projectCache.GetProjectDetailsListFromCache(projectIds);
// return response;
//}
public async Task AddBuildngInfra(Guid projectId, Building? building = null, Floor? floor = null, WorkArea? workArea = null, Guid? buildingId = null)
{
try
@ -70,7 +78,7 @@ namespace Marco.Pms.Services.Helpers
}
catch (Exception ex)
{
_logger.LogWarning("Error occured while adding project infra to Cache: {Error}", ex.Message);
_logger.LogWarning("Error occured while adding project infra for project {ProjectId} to Cache: {Error}", projectId, ex.Message);
}
}
public async Task UpdateBuildngInfra(Guid projectId, Building? building = null, Floor? floor = null, WorkArea? workArea = null, Guid? buildingId = null)
@ -85,7 +93,7 @@ namespace Marco.Pms.Services.Helpers
}
catch (Exception ex)
{
_logger.LogWarning("Error occured while updating project infra to Cache: {Error}", ex.Message);
_logger.LogWarning("Error occured while updating project infra for project {ProjectId} to Cache: {Error}", projectId, ex.Message);
}
}
public async Task<List<BuildingMongoDB>?> GetBuildingInfra(Guid projectId)
@ -97,7 +105,7 @@ namespace Marco.Pms.Services.Helpers
}
catch (Exception ex)
{
_logger.LogWarning("Error occured while getting project infra Cache: {Error}", ex.Message);
_logger.LogWarning("Error occured while getting project infra for project {ProjectId} form Cache: {Error}", projectId, ex.Message);
return null;
}
}
@ -124,7 +132,7 @@ namespace Marco.Pms.Services.Helpers
}
catch (Exception ex)
{
_logger.LogWarning("Error occured while adding projectIds to Cache: {Error}", ex.Message);
_logger.LogWarning("Error occured while adding projectIds for employee {EmployeeId} to Cache: {Error}", employeeId, ex.Message);
return false;
}
}
@ -141,7 +149,7 @@ namespace Marco.Pms.Services.Helpers
}
catch (Exception ex)
{
_logger.LogWarning("Error occured while getting projectIDs to Cache: {Error}", ex.Message);
_logger.LogWarning("Error occured while getting projectIds for employee {EmployeeId} from Cache: {Error}", employeeId, ex.Message);
return null;
}
}
@ -158,7 +166,7 @@ namespace Marco.Pms.Services.Helpers
}
catch (Exception ex)
{
_logger.LogWarning("Error occured while getting permissionIds to Cache: {Error}", ex.Message);
_logger.LogWarning("Error occured while getting permissionIds for employee {EmployeeId} from Cache: {Error}", employeeId, ex.Message);
return null;
}
}
@ -173,10 +181,17 @@ namespace Marco.Pms.Services.Helpers
_logger.LogWarning("Error occured while deleting projectIds from Cache for employee {EmployeeId}: {Error}", employeeId, ex.Message);
}
}
//public async Task ClearAllProjectIdsByRoleId(Guid roleId)
//{
// await _employeeCache.ClearAllProjectIdsByRoleIdFromCache(roleId);
//}
public async Task ClearAllProjectIdsByRoleId(Guid roleId)
{
try
{
await _employeeCache.ClearAllProjectIdsByRoleIdFromCache(roleId);
}
catch (Exception ex)
{
_logger.LogWarning("Error occured while deleting projectIds from Cache for Application Role {RoleId}: {Error}", roleId, ex.Message);
}
}
public async Task ClearAllPermissionIdsByEmployeeID(Guid employeeId)
{
try
@ -185,7 +200,7 @@ namespace Marco.Pms.Services.Helpers
}
catch (Exception ex)
{
_logger.LogWarning("Error occured while deleting permissionIds from to Cache: {Error}", ex.Message);
_logger.LogWarning("Error occured while deleting permissionIds from Cache for employee {EmployeeId}: {Error}", employeeId, ex.Message);
}
}
public async Task ClearAllPermissionIdsByRoleId(Guid roleId)
@ -196,7 +211,7 @@ namespace Marco.Pms.Services.Helpers
}
catch (Exception ex)
{
_logger.LogWarning("Error occured while deleting permissionIds from to Cache: {Error}", ex.Message);
_logger.LogWarning("Error occured while deleting permissionIds from Cache for Application role {RoleId}: {Error}", roleId, ex.Message);
}
}
public async Task RemoveRoleId(Guid employeeId, Guid roleId)
@ -207,7 +222,7 @@ namespace Marco.Pms.Services.Helpers
}
catch (Exception ex)
{
_logger.LogWarning("Error occured while deleting Application roleIds from to Cache: {Error}", ex.Message);
_logger.LogWarning("Error occured while deleting Application role {RoleId} from Cache for employee {EmployeeId}: {Error}", roleId, employeeId, ex.Message);
}
}
}

View File

@ -1,6 +1,7 @@
using Marco.Pms.DataAccess.Data;
using Marco.Pms.Model.Employees;
using Marco.Pms.Model.Entitlements;
using Marco.Pms.Model.MongoDBModels;
using Marco.Pms.Model.Projects;
using Marco.Pms.Services.Helpers;
using Microsoft.EntityFrameworkCore;
@ -58,9 +59,27 @@ namespace MarcoBMS.Services.Helpers
var projectIds = await _cache.GetProjects(LoggedInEmployee.Id);
if (projectIds != null)
{
List<ProjectMongoDB> projectdetails = await _cache.GetProjectDetailsList(projectIds) ?? new List<ProjectMongoDB>();
projects = projectdetails.Select(p => new Project
{
Id = Guid.Parse(p.Id),
Name = p.Name,
ShortName = p.ShortName,
ProjectAddress = p.ProjectAddress,
ProjectStatusId = Guid.Parse(p.ProjectStatus?.Id ?? ""),
ContactPerson = p.ContactPerson,
StartDate = p.StartDate,
EndDate = p.EndDate,
TenantId = tenantId
}).ToList();
if (projects.Count != projectIds.Count)
{
projects = await _context.Projects.Where(p => projectIds.Contains(p.Id)).ToListAsync();
}
}
else
{
var featurePermissionIds = await _cache.GetPermissions(LoggedInEmployee.Id);