From b6ac3073d382bf1ae431deea518e1867bce4b753 Mon Sep 17 00:00:00 2001 From: MahanCh Date: Wed, 30 Apr 2025 16:48:52 +0330 Subject: [PATCH] fix speed workflow employeeDocuments --- .../Repository/EmployeeDocumentsRepository.cs | 313 ++++++++++++------ 1 file changed, 214 insertions(+), 99 deletions(-) diff --git a/CompanyManagment.EFCore/Repository/EmployeeDocumentsRepository.cs b/CompanyManagment.EFCore/Repository/EmployeeDocumentsRepository.cs index 07ddf786..7f0dff9e 100644 --- a/CompanyManagment.EFCore/Repository/EmployeeDocumentsRepository.cs +++ b/CompanyManagment.EFCore/Repository/EmployeeDocumentsRepository.cs @@ -392,48 +392,122 @@ public class EmployeeDocumentsRepository : RepositoryBase GetWorkshopsWithDocumentsAwaitingReviewForAdminWorkFlow(List workshops) { - var activeEmployees = _companyContext.LeftWorkList + //var activeEmployees = _companyContext.LeftWorkList + // .Where(x => workshops.Contains(x.WorkshopId) && x.LeftWorkDate.AddDays(-1) >= DateTime.Now) + // .Select(x => new { x.WorkshopId, x.EmployeeId }); + + //var employeeClientTemp = _companyContext.EmployeeClientTemps.Where(x => workshops.Contains(x.WorkshopId)) + // .Select(x=> new { x.WorkshopId, x.EmployeeId }); + + //var query = _companyContext.EmployeeDocuments + // .Where(x => workshops.Contains(x.WorkshopId) && + // (activeEmployees.Any(y => y.WorkshopId == x.WorkshopId && y.EmployeeId == x.EmployeeId) || + // employeeClientTemp.Any(temp => + // x.EmployeeId == temp.EmployeeId && temp.WorkshopId == x.WorkshopId)) && + // x.IsConfirmed == false) + // .Include(x => x.Workshop).Include(x => x.EmployeeDocumentItemCollection).AsSplitQuery().AsNoTracking() + // .Where(x => x.IsSentToChecker == false && + // (x.EmployeeDocumentItemCollection.Any(y => + // y.DocumentStatus == DocumentStatus.SubmittedByClient) || + // employeeClientTemp.Any(temp => + // x.EmployeeId == temp.EmployeeId && temp.WorkshopId == x.WorkshopId) || x.HasRejectedItems)) + // .GroupBy(x => x.WorkshopId).Select(x => new WorkshopWithEmployeeDocumentsViewModel() + // { + // WorkshopId = x.Key, + // WorkshopFullName = x.FirstOrDefault().Workshop.WorkshopName, + // EmployeesWithoutDocumentCount = x.Count() + // }); + + + + //var workshopEmployers = _companyContext.WorkshopEmployers.Include(x => x.Employer).AsSplitQuery() + // .Where(x => query.Any(y => y.WorkshopId == x.WorkshopId)) + // .GroupBy(x => x.WorkshopId).Select(x => x.FirstOrDefault()).ToList(); + + + + + //var result = query.ToList(); + + + //result.ForEach(x => + //{ + // var employer = workshopEmployers.FirstOrDefault(y => y.WorkshopId == x.WorkshopId)?.Employer; + // x.EmployerName = employer.FullName; + + // //x.SubmittedItems.ForEach(y=>y.PicturePath= medias.FirstOrDefault(z=>z.id == y.MediaId)?.Path ?? ""); + //}); + + //return result.Where(x => x.EmployeesWithoutDocumentCount > 0).OrderByDescending(x => x.EmployeesWithoutDocumentCount).ToList(); + + // یک بار keyها رو آماده می‌کنیم + var activeEmployeeKeys = _companyContext.LeftWorkList .Where(x => workshops.Contains(x.WorkshopId) && x.LeftWorkDate.AddDays(-1) >= DateTime.Now) .Select(x => new { x.WorkshopId, x.EmployeeId }); - var employeeClientTemp = _companyContext.EmployeeClientTemps.Where(x => workshops.Contains(x.WorkshopId)); + var employeeClientTempKeys = _companyContext.EmployeeClientTemps + .Where(x => workshops.Contains(x.WorkshopId)) + .Select(x => new { x.WorkshopId, x.EmployeeId }); - var query = _companyContext.EmployeeDocuments - .Where(x => workshops.Contains(x.WorkshopId) && - (activeEmployees.Any(y => y.WorkshopId == x.WorkshopId && y.EmployeeId == x.EmployeeId) || - employeeClientTemp.Any(temp => x.EmployeeId == temp.EmployeeId && temp.WorkshopId == x.WorkshopId)) && x.IsConfirmed == false) - .Include(x => x.Workshop).Include(x => x.EmployeeDocumentItemCollection) - .Where(x => x.IsSentToChecker == false && - (x.EmployeeDocumentItemCollection.Any(y => - y.DocumentStatus == DocumentStatus.SubmittedByClient) || employeeClientTemp.Any(temp => x.EmployeeId == temp.EmployeeId && temp.WorkshopId == x.WorkshopId) || x.HasRejectedItems)) - .GroupBy(x => x.WorkshopId).Select(x => new WorkshopWithEmployeeDocumentsViewModel() + var allValidKeys = activeEmployeeKeys + .Union(employeeClientTempKeys); + + // کوئری اصلی بدون Include و بدون GroupBy + var employeeDocs = _companyContext.EmployeeDocuments + .Where(x => + workshops.Contains(x.WorkshopId) && + allValidKeys.Any(k => k.WorkshopId == x.WorkshopId && k.EmployeeId == x.EmployeeId) && + !x.IsConfirmed && + !x.IsSentToChecker && + ( + x.EmployeeDocumentItemCollection.Any(y => y.DocumentStatus == DocumentStatus.SubmittedByClient) || + x.HasRejectedItems || + employeeClientTempKeys.Any(k => k.WorkshopId == x.WorkshopId && k.EmployeeId == x.EmployeeId) + )) + .Select(x => new { - WorkshopId = x.Key, - WorkshopFullName = x.FirstOrDefault().Workshop.WorkshopName, - EmployeesWithoutDocumentCount = x.Count() - }); + x.WorkshopId, + WorkshopName = x.Workshop.WorkshopName, + x.EmployeeId + }) + .AsNoTracking() + .ToList(); + // Group در حافظه با سرعت بیشتر + var grouped = employeeDocs + .GroupBy(x => new { x.WorkshopId, x.WorkshopName }) + .Select(g => new WorkshopWithEmployeeDocumentsViewModel + { + WorkshopId = g.Key.WorkshopId, + WorkshopFullName = g.Key.WorkshopName, + EmployeesWithoutDocumentCount = g.Count() + }) + .ToList(); + // گرفتن کارفرماها فقط برای ورکشاپ‌هایی که توی لیست بالا هستن + var workshopIds = grouped.Select(x => x.WorkshopId).ToList(); - var workshopEmployers = _companyContext.WorkshopEmployers.Include(x => x.Employer) - .Where(x => query.Any(y => y.WorkshopId == x.WorkshopId)) - .GroupBy(x => x.WorkshopId).Select(x => x.FirstOrDefault()).ToList(); + var employers = _companyContext.WorkshopEmployers + .Where(x => workshopIds.Contains(x.WorkshopId)) + .Include(x => x.Employer) + .AsSplitQuery() + .AsNoTracking() + .GroupBy(x => x.WorkshopId) + .Select(g => g.FirstOrDefault()) + .ToList(); - - - - var result = query.ToList(); - - - result.ForEach(x => + // اضافه کردن اسم کارفرما + grouped.ForEach(x => { - var employer = workshopEmployers.FirstOrDefault(y => y.WorkshopId == x.WorkshopId)?.Employer; - x.EmployerName = employer.FullName; - - //x.SubmittedItems.ForEach(y=>y.PicturePath= medias.FirstOrDefault(z=>z.id == y.MediaId)?.Path ?? ""); + var employer = employers.FirstOrDefault(y => y.WorkshopId == x.WorkshopId)?.Employer; + x.EmployerName = employer?.FullName; }); - return result.Where(x => x.EmployeesWithoutDocumentCount > 0).OrderByDescending(x => x.EmployeesWithoutDocumentCount).ToList(); + // فیلتر نهایی + return grouped + .Where(x => x.EmployeesWithoutDocumentCount > 0) + .OrderByDescending(x => x.EmployeesWithoutDocumentCount) + .ToList(); } @@ -475,44 +549,83 @@ public class EmployeeDocumentsRepository : RepositoryBase GetByWorkshopIdWithItemsForAdminWorkFlow(long workshopId) { - var activeEmployeesInWorkshop = _companyContext.LeftWorkList - .Where(x => workshopId == x.WorkshopId && x.LeftWorkDate.AddDays(-1) >= DateTime.Today) - .Include(x => x.Employee).ThenInclude(x => x.EmployeeDocuments) - .Select(x => new { x.EmployeeId, FullName = x.Employee.FName + " " + x.Employee.LName, x.Employee.Gender }); - + var activeEmployeeIds = _companyContext.LeftWorkList + .Where(x => x.WorkshopId == workshopId && x.LeftWorkDate.AddDays(-1) >= DateTime.Today) + .Select(x => new + { + x.EmployeeId, + FullName = x.Employee.FName + " " + x.Employee.LName, + x.Employee.Gender + }).ToList(); + + var activeEmployeeIdList = activeEmployeeIds.Select(x => x.EmployeeId).ToList(); + //var EDItemsList = _companyContext.EmployeeDocumentItems + // .Where(x => x.WorkshopId == workshopId && + // x.DocumentStatus != DocumentStatus.Unsubmitted && + // activeEmployeeIdList.Contains(x.EmployeeId)) + // .Include(x => x.EmployeeDocuments) + // .Where(x => x.EmployeeDocuments.IsSentToChecker == false && + // ((x.DocumentStatus == DocumentStatus.SubmittedByClient) || + // x.EmployeeDocuments.HasRejectedItems)) + // .GroupBy(x => new { x.EmployeeId, x.DocumentLabel }) + // .Select(x => + // x.Select(y => new + // { + // y.EmployeeDocumentId, + // Id = y.id, + // y.EmployeeDocuments.Gender, + // y.DocumentLabel, + // y.DocumentStatus, + // y.MediaId, + // y.RejectionReason, + // y.EmployeeId, + // y.CreationDate, + // IsSentToChecker = y.EmployeeDocuments.IsSentToChecker, + // y.EmployeeDocuments.IsConfirmed + // }).OrderByDescending(y => y.CreationDate).First()).ToList(); var EDItemsList = _companyContext.EmployeeDocumentItems - .Where(x => x.WorkshopId == workshopId && x.DocumentStatus != DocumentStatus.Unsubmitted && - activeEmployeesInWorkshop.Any(y => y.EmployeeId == x.EmployeeId)) - .Include(x => x.EmployeeDocuments) - .Where(x => x.EmployeeDocuments.IsSentToChecker == false && - ((x.DocumentStatus == DocumentStatus.SubmittedByClient) || - x.EmployeeDocuments.HasRejectedItems)) + .Where(x => x.WorkshopId == workshopId && + x.DocumentStatus != DocumentStatus.Unsubmitted && + activeEmployeeIdList.Contains(x.EmployeeId) && + x.EmployeeDocuments.IsSentToChecker == false && + (x.DocumentStatus == DocumentStatus.SubmittedByClient || x.EmployeeDocuments.HasRejectedItems)) + .Include(x=>x.EmployeeDocuments).ToList() .GroupBy(x => new { x.EmployeeId, x.DocumentLabel }) - .Select(x => - x.Select(y => new - { - y.EmployeeDocumentId, - Id = y.id, - y.EmployeeDocuments.Gender, - y.DocumentLabel, - y.DocumentStatus, - y.MediaId, - y.RejectionReason, - y.EmployeeId, - y.CreationDate, - IsSentToChecker = y.EmployeeDocuments.IsSentToChecker, - y.EmployeeDocuments.IsConfirmed - }).OrderByDescending(y => y.CreationDate).First()).ToList(); + .Select(g => g.OrderByDescending(x => x.CreationDate).Select(y => new + { + y.EmployeeDocumentId, + Id = y.id, + y.EmployeeDocuments.Gender, + y.DocumentLabel, + y.DocumentStatus, + y.MediaId, + y.RejectionReason, + y.EmployeeId, + y.CreationDate, + y.EmployeeDocuments.IsSentToChecker, + y.EmployeeDocuments.IsConfirmed + }).FirstOrDefault()) + .ToList(); - var employeeClientTemp = _companyContext.EmployeeClientTemps.Where(x => x.WorkshopId == workshopId); - var tempEmployees = _companyContext.Employees.Where(x => employeeClientTemp.Any(a => a.EmployeeId == x.id)) - .Select(x => new { EmployeeId = x.id, FullName = x.FName + " " + x.LName, x.Gender }).ToList(); + var tempEmployeeIds = _companyContext.EmployeeClientTemps + .Where(x => x.WorkshopId == workshopId) + .Select(x => x.EmployeeId) + .ToList(); + + var tempEmployees = _companyContext.Employees + .Where(x => tempEmployeeIds.Contains(x.id)) + .Select(x => new + { + EmployeeId = x.id, + FullName = x.FName + " " + x.LName, + x.Gender + }).ToList(); var tempEmployeeDocuments = _companyContext.EmployeeDocuments - .Where(x => x.WorkshopId == workshopId && employeeClientTemp.Any(e => e.EmployeeId == x.EmployeeId) && + .Where(x => x.WorkshopId == workshopId && tempEmployeeIds.Contains(x.EmployeeId) && x.IsSentToChecker == false && x.IsConfirmed == false) .SelectMany(x => x.EmployeeDocumentItemCollection.DefaultIfEmpty(), // اگر خالی بود، مقدار پیش‌فرض ایجاد کن (documents, y) => new @@ -533,55 +646,57 @@ public class EmployeeDocumentsRepository : RepositoryBase x.MediaId).ToList(); - var mediasList = _accountContext.Medias.Where(x => mediaIds.Contains(x.id)) + var mediaIds = allEmployeeDocuments.Select(x => x.MediaId).ToList(); + + var mediasList = _accountContext.Medias + .Where(x => mediaIds.Contains(x.id)) .Select(x => new MediaViewModel() { Id = x.id, Path = x.Path }).ToList(); - var result = enumerable.GroupBy(x => x.EmployeeId) - .Select(x => + var result = allEmployeeDocuments + .GroupBy(x => x.EmployeeId) + .Select(group => { - //var requiredDocs = EmployeeDocumentRequiredItems.GetByGender(x.Gender); - var employeeLatestConfirmedDocuments = x + var employee = allEmployees.First(e => e.EmployeeId == group.Key); - .Where(y => y.EmployeeId == x.Key && (y.DocumentStatus == DocumentStatus.SubmittedByClient || y.DocumentStatus == DocumentStatus.SubmittedByAdmin || y.DocumentStatus == DocumentStatus.Rejected)) - .Select(y => new EmployeeDocumentItemViewModel() + var docs = group + .Where(y => y.DocumentStatus == DocumentStatus.SubmittedByClient || + y.DocumentStatus == DocumentStatus.SubmittedByAdmin || + y.DocumentStatus == DocumentStatus.Rejected) + .Select(y => new EmployeeDocumentItemViewModel + { + Status = y.DocumentStatus, + MediaId = y.MediaId, + DocumentItemLabel = y.DocumentLabel, + Id = y.Id, + RejectionMessage = y.RejectionReason, + StatusString = y.DocumentStatus.ToString() + }).ToList(); + + return new EmployeeDocumentsViewModel { - Status = y.DocumentStatus, - MediaId = y.MediaId, - DocumentItemLabel = y.DocumentLabel, - Id = y.Id, - RejectionMessage = y.RejectionReason, - StatusString = y.DocumentStatus.ToString() - }).ToList(); - - - //var requiredItemsUploaded = employeeLatestConfirmedDocuments - // .Where(y => requiredDocs.Contains(y.DocumentItemLabel)).Select(y => y.DocumentItemLabel) - // .ToList(); - - return new EmployeeDocumentsViewModel() - { - EmployeeId = x.Key, - IdCardPage1 = GetByLabelAndLoadMedia(employeeLatestConfirmedDocuments, mediasList, DocumentItemLabel.IdCardPage1), - IdCardPage2 = GetByLabelAndLoadMedia(employeeLatestConfirmedDocuments, mediasList, DocumentItemLabel.IdCardPage2), - IdCardPage3 = GetByLabelAndLoadMedia(employeeLatestConfirmedDocuments, mediasList, DocumentItemLabel.IdCardPage3), - IdCardPage4 = GetByLabelAndLoadMedia(employeeLatestConfirmedDocuments, mediasList, DocumentItemLabel.IdCardPage4), - EducationalDegree = GetByLabelAndLoadMedia(employeeLatestConfirmedDocuments, mediasList, DocumentItemLabel.EducationalDegree), - EmployeeFullName = activeEmployeesInWorkshopList.First(y => y.EmployeeId == x.Key).FullName, - NationalCardFront = GetByLabelAndLoadMedia(employeeLatestConfirmedDocuments, mediasList, DocumentItemLabel.NationalCardFront), - NationalCardRear = GetByLabelAndLoadMedia(employeeLatestConfirmedDocuments, mediasList, DocumentItemLabel.NationalCardRear), - MilitaryServiceCard = GetByLabelAndLoadMedia(employeeLatestConfirmedDocuments, mediasList, DocumentItemLabel.MilitaryServiceCard), - EmployeePicture = GetByLabelAndLoadMedia(employeeLatestConfirmedDocuments, mediasList, DocumentItemLabel.EmployeePicture), - //RequiredDocumentsUploaded = requiredItemsUploaded, - //RequiredDocuments = requiredDocs + EmployeeId = group.Key, + IdCardPage1 = GetByLabelAndLoadMedia(docs, mediasList, DocumentItemLabel.IdCardPage1), + IdCardPage2 = GetByLabelAndLoadMedia(docs, mediasList, DocumentItemLabel.IdCardPage2), + IdCardPage3 = GetByLabelAndLoadMedia(docs, mediasList, DocumentItemLabel.IdCardPage3), + IdCardPage4 = GetByLabelAndLoadMedia(docs, mediasList, DocumentItemLabel.IdCardPage4), + EducationalDegree = GetByLabelAndLoadMedia(docs, mediasList, DocumentItemLabel.EducationalDegree), + EmployeeFullName = employee.FullName, + NationalCardFront = GetByLabelAndLoadMedia(docs, mediasList, DocumentItemLabel.NationalCardFront), + NationalCardRear = GetByLabelAndLoadMedia(docs, mediasList, DocumentItemLabel.NationalCardRear), + MilitaryServiceCard = GetByLabelAndLoadMedia(docs, mediasList, DocumentItemLabel.MilitaryServiceCard), + EmployeePicture = GetByLabelAndLoadMedia(docs, mediasList, DocumentItemLabel.EmployeePicture), }; - }).ToList(); + }) + .ToList(); return result;