/// <summary> /// Check for duplicates coils. When found the original entry /// and its readings are removed. /// </summary> /// <param name="context"></param> /// <param name="coilNumber"></param> /// <returns></returns> public bool CheckForDuplicates(CoilStoreContext context, string coilNumber, string dataType) { string marker = "Begin."; try { Coil coil = context.Coils.SingleOrDefault(rr => (rr.CoilNumber == coilNumber) && (rr.DataType == dataType)); if (coil == null) // no duplicates { return(true); } // Find and remove the readings marker = string.Format("Found coil with ID={0} and DataType={1}. Finding CoilReadings...", coilNumber, dataType); List <CoilReading> readingsList = context.CoilReadings.Where(rr => rr.CoilId == coil.CoilId).ToList(); marker = string.Format("Removing {0} CoilReadings...", readingsList.Count()); context.CoilReadings.RemoveRange(readingsList); marker = string.Format("Removing coil..."); // ... and then remove the parent context.Coils.Remove(coil); logit(string.Format("Removing duplicate coil={0} (type={1}) and its {2} child readings", coil.CoilNumber, coil.DataType, readingsList.Count())); context.SaveChanges(); return(true); } catch (Exception ex) { logit(string.Format("Removing Coil={0} Marker={1} Err={2}", coilNumber, marker, ex.ToString())); return(false); } } // method
} // method /// <summary> /// Parse the file and store the results. Here is an example: /// 01350000,9/14/13 10:41:39 /// 1 /// 1317 /// Actual,Ordered,Pos Tol,Neg Tol /// 1707.069092,1640,1680,1520 /// 1684.532349 /// 1705.388794 /// ... /// </summary> /// <param name="fe"></param> /// <returns></returns> public bool ParseAndStoreFile(FileEntry fe, out string explanation) { explanation = ""; try { StringBuilder sbReadings = new StringBuilder(); int numberOfReadings = 0; Int64 parentCoilId = -1; string[] lines = File.ReadAllLines(fe.FilePath); int suffix = 0; string extension = Path.GetExtension(fe.FilePath); // remove the initial '.' and lowercase the extension if (extension.Length < 2) { explanation = string.Format("File={0}. Expected a legal extension on the file."); return(false); } extension = extension.ToLower().Substring(1); switch (extension) { case "fdh": suffix = 1; break; case "fdw": suffix = 2; break; default: explanation = string.Format("File={0} had unknown extension={1}", fe.FilePath, extension); return(false); } // Add the coil and readings within a transaction ////using ( TransactionScope scope = new TransactionScope()) ////{ using (CoilStoreContext context = new CoilStoreContext()) { // We're only inserting here, so the following will speed things up. context.Configuration.AutoDetectChangesEnabled = false; //context.Configuration.ValidateOnSaveEnabled = false; Coil newCoil = new Coil(); newCoil.CreationTimeUTC = DateTime.UtcNow; int readingCount = 0; int count = 0; foreach (String line in lines) { count += 1; string[] tokens; switch (count) { case 1: // coil number and date tokens = line.Split(','); if (tokens.Length != 2) { explanation = string.Format("File={0} Line={1}({2}) does not have two tokens."); return(false); } newCoil.CoilNumber = tokens[0]; // Check if the coil already exists. // If it does, then we'll delete the existing coil and records before continuing if (!CheckForDuplicates(context, newCoil.CoilNumber, extension.ToLower())) { logit(String.Format("Cannot remove duplicate coil={0}. Cannot continue with file={1}", newCoil.CoilNumber, fe.FilePath)); return(false); } DateTimeOffset dto; if (!DateTimeOffset.TryParse(tokens[1], out dto)) { explanation = string.Format("Cannot parse Date={0}", tokens[1]); return(false); } newCoil.ProducedTime = dto; newCoil.DataType = extension; // {Nov2015/dth} convert to UTC DateTimeOffset dtoUtc = dto.ToUniversalTime(); // Build the key from the data and the file type newCoil.CoilId = BuildCoilKey(dtoUtc, suffix); // Look for duplicates Coil checkCoil = context.Coils.SingleOrDefault(rr => rr.CoilId == newCoil.CoilId); if (checkCoil != null) { explanation = String.Format("Coil with Key={0} Already exists. CoilNumber={1}", newCoil.CoilId, newCoil.CoilNumber.ToString()); return(false); } break; case 2: // Gage in use int inUse = 0; if (!int.TryParse(line, out inUse)) { explanation = string.Format("Cannot parse Gage-In-Use. line={0}", line); return(false); } newCoil.GageInUse = inUse; break; case 3: // number of readings if (!int.TryParse(line, out numberOfReadings)) { explanation = string.Format("File={0} Line={1}({2}) reading count must be an integer."); return(false); } newCoil.NumberOfReadings = numberOfReadings; break; case 4: // headers /// Actual,Ordered,Pos Tol,Neg Tol /// 1707.069092,1640,1680,1520 break; case 5: // statistics tokens = line.Split(','); if (tokens.Length != 4) { explanation = string.Format("File={0} Line={1}({2}) does not have four tokens."); return(false); } decimal dd; if (decimal.TryParse(tokens[1], out dd)) { newCoil.OrderValue = dd; } if (decimal.TryParse(tokens[2], out dd)) { newCoil.PositiveTolerance = dd; } if (decimal.TryParse(tokens[3], out dd)) { newCoil.NegativeTolerance = dd; } // This is the last 'parent' record. context.Coils.Add(newCoil); context.SaveChanges(); parentCoilId = newCoil.CoilId; // The first token is the first reading. if (decimal.TryParse(tokens[0], out dd)) { readingCount += 1; CoilReading reading = new CoilReading(); reading.CoilReadingId = BuildCoilReadingKey(newCoil.CoilId, readingCount); reading.CoilId = newCoil.CoilId; reading.ReadingNumber = readingCount; reading.Value = dd; context.CoilReadings.Add(reading); sbReadings.Append(dd.ToString("0.000000")); } break; default: // 6 and above are the rest of the coil readings { // There should be as many readings as were sepcified in case 3: CoilReading reading = new CoilReading(); //reading if (!decimal.TryParse(line, out dd)) { explanation = string.Format("Reading ({0}) cannot parse this={1}", line); return(false); } readingCount += 1; ////// Every 100 readings save the changes ////if ( (readingCount % 100) == 0 ) ////{ //// context.SaveChanges(); //// context = new CoilStoreContext(); //// context.Configuration.AutoDetectChangesEnabled = false; ////} reading.CoilReadingId = BuildCoilReadingKey(newCoil.CoilId, readingCount); reading.CoilId = newCoil.CoilId; reading.ReadingNumber = readingCount; reading.Value = dd; context.CoilReadings.Add(reading); if (readingCount > numberOfReadings) { explanation = string.Format("Readings (currently={0} exceeds the Number in the header={1}", readingCount, newCoil.NumberOfReadings); return(false); } // The readings are also kept in a comma-list field. Append the reading sbReadings.Append("," + dd.ToString("0.000000")); } break; } // switch } // for each if (readingCount != numberOfReadings) { logit(string.Format("Warning: Mismatch on readings. Found={0}, but header said={1}", readingCount, numberOfReadings)); } // Update the coil record context.SaveChanges(); ////scope.Complete(); } // using context ////} // using transactionscope // {Jan2016/dth} Put the lokup and update outside the transaction if ((parentCoilId != -1) && (numberOfReadings > 0)) { using (CoilStoreContext context = new CoilStoreContext()) { Coil newCoil = context.Coils.Find(parentCoilId); if (newCoil != null) { string ss = sbReadings.ToString(); newCoil.Readings = ss; context.SaveChanges(); logit(string.Format("Info: Coil={0} saved, along with {1} CoilRecords", newCoil.CoilNumber, numberOfReadings)); } else { logit(string.Format("Info: Coil File={0} could not be processed.", fe.FilePath)); return(false); } } // using } return(true); } catch (Exception ex) { explanation = string.Format("{0}", ex.ToString()); logit(ex.ToString()); return(false); } } // method