public CoupaImporterJobDefinitionDTO ProcessInvoiceImportJob(Guid jobDefinitionId) { var jobDefinition = _coupaImporterRepository.Get(jobDefinitionId); var allInvoices = new List <InvoiceDTO>(); var invoiceHeaders = new List <InvoiceHeader>(); if (jobDefinition == null) { return(null); } _unitOfWork.AutoDetectChanges(false); // Here we use 1000 records batch so that we can reduce the number of loops. var noOfRotation = jobDefinition.CoupaImporterJobDefinitionDetails.Count() / 1000; noOfRotation += jobDefinition.CoupaImporterJobDefinitionDetails.Count() % 1000 > 0 ? 1 : 0; for (var i = 0; i < noOfRotation; i++) { var strCoupaImporterJobDefinitionDetails = "[ "; strCoupaImporterJobDefinitionDetails += string.Join(", ", jobDefinition.CoupaImporterJobDefinitionDetails .Skip(i * 1000).Take(1000).Select(x => x.RawContent)); strCoupaImporterJobDefinitionDetails += " ]"; // Convert the RawContent to Invoice Header invoiceHeaders.AddRange(JsonConvert.DeserializeObject <List <InvoiceHeader> >(strCoupaImporterJobDefinitionDetails)); // Convert the RawContent to InvoiceDTO allInvoices.AddRange(JsonConvert.DeserializeObject <List <InvoiceDTO> >(strCoupaImporterJobDefinitionDetails)); } // In every InvoiceHeader Entity ProjectId is added invoiceHeaders.ForEach(i => { i.ProjectId = jobDefinition.ProjectId; i.Id = Guid.NewGuid(); }); // Grouping InvoiceHeaders in terms of Unique combination of Supplier & InvoiceNumber invoiceHeaders = invoiceHeaders.GroupBy(i => new { i.InvoiceNumber, i.Supplier }).Select(x => x.First()).ToList(); foreach (var objInvoiceHeader in invoiceHeaders) { // Allocate all line items for a invoice header + InvoiceHeaderId added in every associated Line Items. objInvoiceHeader.InvoiceLineItems = allInvoices.Where(x => x.Supplier == objInvoiceHeader.Supplier && x.InvoiceNumber == objInvoiceHeader.InvoiceNumber) .Select(x => InvoiceLineItem.MapFromDomainEntity(InvoiceDTO.MapToInvoiceLineItemDTO(x))).ToList(); objInvoiceHeader.InvoiceLineItems.ToList().ForEach(x => x.InvoiceHeaderId = objInvoiceHeader.Id); _projectInvoiceRepository.Add(objInvoiceHeader); } // At last update all job definition details records jobDefinition.CoupaImporterJobDefinitionDetails.ToList().ForEach(c => { c.IsProcessed = true; c.IsSuccessful = true; }); _coupaImporterRepository.UpdateAllJobDefinitionDetail(jobDefinitionId, jobDefinition.CoupaImporterJobDefinitionDetails); jobDefinition.Status = (int)CoupaImporterStatus.Processed; _coupaImporterRepository.Update(jobDefinitionId, jobDefinition); _unitOfWork.SaveChanges(); _unitOfWork.AutoDetectChanges(true); return(CoupaImporterJobDefinitionDTO.MapFromDatabaseEntity(jobDefinition)); }