diff --git a/Analysis/CjlrForm/FileSorter.cs b/Analysis/CjlrForm/FileSorter.cs index 3e650d8..bc2b476 100644 --- a/Analysis/CjlrForm/FileSorter.cs +++ b/Analysis/CjlrForm/FileSorter.cs @@ -10,6 +10,19 @@ using System.Text; namespace NSAnalysis { + /// + /// CSV解析结果,替代全局静态变量 ConfigDfn.strEquipNo 等,消除多线程竞争 + /// + public class CsvParseResult + { + public string CarID { get; set; } + public string CarModel { get; set; } + public string Position { get; set; } + public string GroupName { get; set; } + public string MeasureTime { get; set; } + public bool Success { get; set; } + } + public class FileSorter { public CjlrDAL _dal = new CjlrDAL(); @@ -21,6 +34,650 @@ namespace NSAnalysis public event Action OnLog; // 日志事件 + public event Action OnFileParsed; // 解析完成后通知:车号、位置、测量时间 + + // 关键流程节点日志事件 + public event Action OnProcessStep; // 处理步骤日志事件 + + // 封装 OnProcessStep 事件 + private void emitProcessStep(string message) + { + OnProcessStep?.Invoke(message); + } + + public FileSorter() + { + } + + // 主逻辑处理 + public void ProcessFiles() + { + var tasks = GetTaskRecords(); + // 增加空检查 + if (tasks == null || tasks.Rows.Count == 0) + { + Trace("没有找到任何任务记录,处理终止。"); + return; + } + + Trace($"[ProcessFiles] 共查询到 {tasks.Rows.Count} 个分发任务,开始逐一执行。"); + + foreach (DataRow task in tasks.Rows) + { + string modelName = task["modelsName"].ToString(); + string modelCode = task["modelsCode"].ToString(); + string position = task["position"].ToString(); + string sourceDir = task["sourceFile"].ToString(); + string targetDir = task["targetFile"].ToString(); + + // 打印信息 + Trace($"[ProcessFiles] 正在执行分发任务 - 源路径: {sourceDir}, 目标路径: {targetDir}, 匹配字符: {modelCode} 位置:{position}"); + if (Directory.Exists(sourceDir)) + { + ProcessDirectory(sourceDir, targetDir, modelCode, modelName, position); + } + else + { + Trace($"[ProcessFiles] 源文件地址不存在或错误: {sourceDir}"); + } + } + } + + // 获取任务记录 + private DataTable GetTaskRecords() + { + DataTable dt = _dal.SelectTaskByCondition("", "", "start"); + + if (dt == null || dt.Rows.Count == 0) + { + Trace("未发现移动任务."); + return null; + } + return dt; + } + + // 处理目录中的文件 + private void ProcessDirectory(string sourceDir, string targetDir, string modelCode, string modelName, string position) + { + // 匹配信息 + string matchStr = $"{modelCode}_{position}"; + Trace($"匹配文件特征符: {matchStr}"); + + // 确保目标目录存在 + if (!Directory.Exists(targetDir)) + { + Directory.CreateDirectory(targetDir); + Trace($"创建目标文件夹: {targetDir}"); + } + + // 遍历源目录中的所有CSV文件 + foreach (string file in Directory.GetFiles(sourceDir, "*.csv")) + { + // 打印正在处理的文件 + Trace($"正在处理文件 : {file}"); + + // 解析入库,返回局部结果,不再写全局变量 + CsvParseResult parseResult = AnalysisNxsCSV(file); + + // 如果未启用分发功能,直接返回 + if (!ConfigDfn.iEnableSort) + { + return; + } + + #region 分发逻辑 + + if (MatchCsvValue(file, matchStr, readRowIndex, readColIndex)) + { + // 记录日志,匹配到 + Trace($"匹配成功,准备移动文件: {file} -> {targetDir}"); + + string destFile = Path.Combine(targetDir, Path.GetFileName(file)); + if (File.Exists(destFile)) + { + string backupFile = destFile + ".bak_" + DateTime.Now.ToString("yyyyMMdd_HHmmss"); + File.Move(destFile, backupFile); + Trace($"目标文件已存在,已重命名为备份文件: {backupFile}"); + } + File.Move(file, destFile); + Trace($"移动完成,: {file} -> {destFile}"); + emitProcessStep($"---> 5、文件移动完成: -> {destFile}"); + + //插入分发详情 + CjlrTaskReleaseDetailModel detailModel = new CjlrTaskReleaseDetailModel + { + ModelsName = modelName, + ModelsCode = modelCode, + Position = position, + SourceFile = file, + TargetFile = destFile, + TaskFileName = Path.GetFileName(file), + TaskStatus = 1, + TaskDetail = "文件移动成功", + CreateDate = DateTime.Now + }; + _dal.InsertTaskDetail(detailModel); + } + else + { + Trace($"未匹配到文件: {file}"); + emitProcessStep($"---> 5、未匹配到文件: {file}"); + + //记录到数据库 + CjlrTaskReleaseDetailModel detailModel = new CjlrTaskReleaseDetailModel + { + ModelsName = modelName, + ModelsCode = modelCode, + Position = position, + SourceFile = file, + TargetFile = "", + TaskFileName = Path.GetFileName(file), + TaskStatus = 2, + TaskDetail = "文件未匹配", + CreateDate = DateTime.Now + }; + try + { + _dal.InsertTaskDetail(detailModel); + } + catch (Exception ex) + { + Trace($"记录错误到数据库失败: {ex.Message}"); + } + } + + #endregion 分发逻辑 + } + } + + /// + /// 检查CSV文件中指定行列的字符串是否匹配目标值 + /// + public static bool MatchCsvValue(string filePath, string targetValue, int rowIndex, int colIndex) + { + MyBase.TraceWriteLine($"[MatchCsvValue] 检查文件: {filePath}, 行索引: {rowIndex}, 列索引: {colIndex}, 目标值: {targetValue}"); + try + { + string[] lines = File.ReadAllLines(filePath); + + if (rowIndex < 0 || rowIndex >= lines.Length) + return false; + + string[] columns = lines[rowIndex].Split(','); + + if (colIndex < 0 || colIndex >= columns.Length) + return false; + + return columns[colIndex].Trim().Contains(targetValue); + } + catch (Exception ex) + { + MyBase.TraceWriteLine($"处理CSV文件时出错: {ex.Message}"); + return false; + } + } + + // 生成单侧统计信息的方法(使用局部参数,不再依赖全局变量) + private void GenerateSingleSideStatistics(string carID, string carModel, string groupName, string position, string measureTime) + { + #region 统计信息显示 + + DataTable sampleData = _dal.SelectMeasureResultByCarID(carID, groupName); + if (sampleData == null || sampleData.Rows.Count == 0) + { + MyBase.TraceWriteLine("没有测量数据,无法生成统计信息。"); + emitProcessStep(position + " 没有测量数据,无法生成统计信息。"); + return; + } + + AnalysisResult analysis = AnalysisResult.AnalyzeMeasureData(sampleData); + + int dtRowCount = analysis.TotalCount; + double OutCount = analysis.OutCount; + double OKCount = analysis.OKCount; + double RejectedCount = analysis.RejectedCount; + double FPYPercent = analysis.FPYPercent; + + TMeasureResultModel tmrm = new TMeasureResultModel(); + + FPYPercent = OKCount / (OKCount + OutCount); + if (FPYPercent >= ConfigDfn.dFPY) + { + tmrm.Result = 1; + } + else if (FPYPercent >= ConfigDfn.dFPY2 && FPYPercent < ConfigDfn.dFPY) + { + tmrm.Result = 1; + } + else + { + tmrm.Result = 2; + } + + tmrm.CarID = carID; + tmrm.CarType = carModel; + tmrm.SumMeasureItems = dtRowCount; + tmrm.GoodMeasureItems = (int)OKCount; + tmrm.NoGoodMeasureItems = (int)OutCount; + tmrm.RejectMeasureItems = (int)RejectedCount; + tmrm.FPY = FPYPercent.ToString("F4"); + tmrm.Remark = position; + tmrm.MeasureDate = measureTime; + _dal.InsertTMeasureResult(tmrm); + + MyBase.TraceWriteLine("将总结果插入数据库完毕。"); + emitProcessStep($"---> 3、统计信息已生成: 位置: {position}, 总测量项: {dtRowCount}, 合格项: {OKCount}, 不合格项: {OutCount}, 异常项: {RejectedCount}, FPY: {FPYPercent:F4}"); + + #endregion 统计信息显示 + } + + // 导入CSV文件到数据库,返回解析结果(不再写全局变量) + public CsvParseResult ImportCsv2Sql(string filePath) + { + var result = new CsvParseResult { Success = false }; + var records = new List(); + var lineNo = 0; + var groupName = string.Empty; + var position = string.Empty; + + emitProcessStep($"正在处理: {filePath}"); + + // 判断文件是否已经处理过 + if (_dal.IsFileProcessed(filePath)) + { + MyBase.TraceWriteLine($"文件已处理过,跳过: {filePath}"); + emitProcessStep($"---> 2、文件已处理过,跳过: {filePath}"); + return result; + } + + // 备份原始文件 + try + { + string backupDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Backup"); + if (!Directory.Exists(backupDir)) + { + Directory.CreateDirectory(backupDir); + } + string backupFilePath = Path.Combine(backupDir, Path.GetFileName(filePath)); + File.Copy(filePath, backupFilePath, true); + MyBase.TraceWriteLine("已备份文件到: " + backupFilePath); + } + catch (Exception ex) + { + MyBase.TraceWriteLine("备份文件时发生错误:" + ex.Message); + } + + try + { + using (var reader = new StreamReader(filePath)) + { + reader.ReadLine(); // Skip header + + lineNo = 1; + while (!reader.EndOfStream) + { + lineNo++; + var line = reader.ReadLine(); + var values = line.Split(','); + + if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#") || line.StartsWith("//") || line.StartsWith("MeasPoint.Name")) + { + continue; + } + + if (values.Length < 22) + { + MyBase.TraceWriteLine("CSV行数据不完整,跳过该行:" + line); + continue; + } + + if (string.IsNullOrEmpty(values[2])) + { + MyBase.TraceWriteLine($"第 {lineNo} 行数据为0,跳过该行:" + line); + continue; + } + + var record = new CJLR_MeaDataModel + { + PointName = values[0], + GroupName = values[1], + ProductNum = values[2], + Model = values[3], + Station = values[4], + Method = values[5], + Standard = values[6], + DimensionName = values[7], + DimensionValue = values[8], + DimensionUnit = values[9], + IsManual = bool.Parse(values[10]), + Classification = values[11], + ToleranceName0 = values[12], + ToleranceLower0 = values[13], + ToleranceUpper0 = values[14], + ToleranceName1 = values[15], + ToleranceLower1 = values[16], + ToleranceUpper1 = values[17], + NominalValue = values[18], + MeasureDate = DateTime.ParseExact(values[19], "yyyyMMdd", CultureInfo.InvariantCulture), + MeasureTime = TimeSpan.ParseExact(values[20], "hhmmss", CultureInfo.InvariantCulture), + SequenceNum = int.Parse(values[21]) + }; + + records.Add(record); + } + } + } + catch (Exception ex) + { + MyBase.TraceWriteLine("导入CSV文件时发生错误:" + ex.Message); + emitProcessStep($"---> 2、导入CSV文件时发生错误: {ex.Message}"); + + string errorDir = Path.Combine(Path.GetDirectoryName(filePath), "Error"); + if (!Directory.Exists(errorDir)) + { + Directory.CreateDirectory(errorDir); + } + string errorFilePath = Path.Combine(errorDir, Path.GetFileName(filePath)); + File.Move(filePath, errorFilePath); + MyBase.TraceWriteLine("已将文件移动到错误文件夹: " + errorFilePath); + return result; + } + + try + { + if (records.Count > 0) + { + var firstRecord = records[0]; + + // 所有解析结果存入局部变量,不写全局 ConfigDfn + result.MeasureTime = firstRecord.MeasureDate.ToString("yyyy-MM-dd") + " " + firstRecord.MeasureTime.ToString(@"hh\:mm\:ss"); + result.CarID = firstRecord.ProductNum; + result.CarModel = firstRecord.Model; + + groupName = firstRecord.GroupName; + result.GroupName = groupName; + + MyBase.TraceWriteLine("测量时间:" + result.MeasureTime); + MyBase.TraceWriteLine("--------------------------------------------------------"); + MyBase.TraceWriteLine("车号:" + result.CarID); + MyBase.TraceWriteLine("车型:" + result.CarModel); + MyBase.TraceWriteLine("组名:" + groupName); + + if (string.IsNullOrEmpty(firstRecord.GroupName)) + { + MyBase.TraceWriteLine("组名为空,使用默认位置。"); + result.Position = "Default"; + } + else + { + var parts2 = firstRecord.GroupName.Split('_'); + if (parts2.Length > 1 && !string.IsNullOrEmpty(parts2[1])) + { + result.Position = parts2[1].Substring(0, 1); + } + else + { + result.Position = firstRecord.GroupName; + } + } + + MyBase.TraceWriteLine("位置:" + result.Position); + MyBase.TraceWriteLine("测量时间:" + result.MeasureTime); + + emitProcessStep($"---> 1、解析到, 车号: {result.CarID} 车型: {result.CarModel} 位置: {result.Position} 测量时间: {result.MeasureTime}"); + } + else + { + MyBase.TraceWriteLine("没有找到有效的测量记录,无法设置测量时间。CSV文件导入到数据库失败!"); + emitProcessStep($"---> 2、没有找到有效的测量记录,无法设置测量时间。CSV文件导入到数据库失败!"); + + string errorDir = Path.Combine(Path.GetDirectoryName(filePath), "Error"); + if (!Directory.Exists(errorDir)) + { + Directory.CreateDirectory(errorDir); + } + string errorFilePath = Path.Combine(errorDir, Path.GetFileName(filePath)); + File.Move(filePath, errorFilePath); + MyBase.TraceWriteLine("已将文件移动到错误文件夹: " + errorFilePath); + return result; + } + + // 逐条插入数据到数据库 + foreach (var record in records) + { + _dal.InsertOrUpdateCJLRMeaData(record); + } + + // 记录处理文件到数据库 + _dal.InsertProcessedFile(filePath); + MyBase.TraceWriteLine("CSV文件导入到数据库成功!"); + emitProcessStep($"---> 2、CSV文件导入到数据库成功"); + + result.Success = true; + + #region 处理单侧统计信息 + + GenerateSingleSideStatistics(result.CarID, result.CarModel, groupName, result.Position, result.MeasureTime); + + #endregion 处理单侧统计信息 + + MyBase.TraceWriteLine("--------------------------------------------------------"); + } + catch (Exception ex) + { + MyBase.TraceWriteLine("导入CSV文件时发生错误:" + ex.Message); + emitProcessStep($"---> 2、导入CSV文件时发生错误: {ex.Message}"); + } + + return result; + } + + // 解析CSV文件,返回解析结果(不再依赖/写入全局变量) + public CsvParseResult AnalysisNxsCSV(string strCSVName) + { + var emptyResult = new CsvParseResult { Success = false }; + + if (!File.Exists(strCSVName)) + { + MyBase.TraceWriteLine("文件不存在:" + strCSVName); + return emptyResult; + } + + try + { + // 解析 CSV 文件并导入到数据库,获取局部结果 + CsvParseResult parseResult = ImportCsv2Sql(strCSVName); + + if (!parseResult.Success || string.IsNullOrEmpty(parseResult.CarID)) + { + return parseResult; + } + + // 解析完成后触发事件,传递局部结果(不依赖全局变量) + Trace($"触发事件,车号: {parseResult.CarID} 位置: {parseResult.Position}"); + OnFileParsed?.Invoke(parseResult.CarID, parseResult.Position, parseResult.MeasureTime); + + // 检查是否有双侧测量结果(防御性检查) + bool isMeasureComplete = _dal.HasBothSidesMeasureResult(parseResult.CarID); + + if (isMeasureComplete) + { + MyBase.TraceWriteLine("双侧测量结果已完成,开始生成客户报告。"); + emitProcessStep($"---> 4、双侧测量结果已完成,开始生成客户报告,车号: {parseResult.CarID}"); + + if (parseResult.CarModel != null && parseResult.CarModel.Contains("MY")) + { + MyBase.TraceWriteLine("车型为 551_MY21,跳过客户报告生成。"); + emitProcessStep($"---> 4、车型为 551_MY21,跳过客户报告生成,车号: {parseResult.CarID}"); + return parseResult; + } + + GenCustomerReport(parseResult.CarID, parseResult.CarModel); + } + else + { + MyBase.TraceWriteLine("双侧测量结果未完成,跳过客户报告生成。"); + emitProcessStep($"---> 4、双侧测量结果未完成,跳过客户报告生成,车号: {parseResult.CarID}"); + } + + return parseResult; + } + catch (Exception ex) + { + MyBase.TraceWriteLine("解析 CSV 文件时发生错误:" + ex.Message); + return emptyResult; + } + } + + // 生成客户报告函数(使用参数传入,不依赖全局变量) + private void GenCustomerReport(string strCarID, string carModel) + { + DataTable dtCSVContent = _dal.SelectPointDimensionByCarID(strCarID); + + if (dtCSVContent == null || dtCSVContent.Rows.Count == 0) + { + MyBase.TraceWriteLine("没有找到测量数据,无法生成客户报告。"); + return; + } + + string fileName = strCarID + "_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".csv"; + + if (!Directory.Exists(ConfigDfn.strReportPath)) + { + Directory.CreateDirectory(ConfigDfn.strReportPath); + MyBase.TraceWriteLine($"创建报告目录: {ConfigDfn.strReportPath}"); + } + + string backupDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ReportBackup"); + if (!Directory.Exists(backupDir)) + { + Directory.CreateDirectory(backupDir); + } + + string savePath = Path.Combine(backupDir, fileName); + string target = Path.Combine(ConfigDfn.strReportPath, fileName); + + GenerateCsvReport(strCarID, carModel, dtCSVContent, ConfigDfn.strCSVReportTemplatePath, savePath); + + MyBase.TraceWriteLine($"客户报告已生成: {savePath}"); + emitProcessStep($"---> 5、客户报告已生成: {savePath}"); + try + { + File.Copy(savePath, target, true); + MyBase.TraceWriteLine("已拷贝客户报告到目标路径: " + target); + emitProcessStep($"---> 6、已拷贝客户报告到目标路径: {target}"); + } + catch + { + MyBase.TraceWriteLine("拷贝客户报告到目标路径失败: " + target); + emitProcessStep($"---> 6、拷贝客户报告到目标路径失败: {target}"); + } + } + + // 生成CSV报告函数(carModel 作为参数传入,不依赖全局变量) + private void GenerateCsvReport(string strCarID, string carModel, DataTable measureData, string templatePath, string savePath) + { + var templateLines = File.ReadAllLines(templatePath); + + StringBuilder sb = new StringBuilder(); + + foreach (var line in templateLines) + { + string processedLine = line; + if (processedLine.Contains("{datetime}")) + { + processedLine = processedLine.Replace("{datetime}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)); + } + if (processedLine.Contains("{Part_ident}")) + { + processedLine = processedLine.Replace("{Part_ident}", strCarID); + } + if (processedLine.Contains("{model}")) + { + processedLine = processedLine.Replace("{model}", carModel); + } + if (processedLine.Contains("{Part_code}")) + { + if (carModel == "E03") + processedLine = processedLine.Replace("{Part_code}", "E03_5000000FAonline"); + else if (carModel == "E0Y") + processedLine = processedLine.Replace("{Part_code}", "E0Y_5000000FAonline"); + else + processedLine = processedLine.Replace("{Part_code}", "UnknownModel_5000000FAonline"); + } + processedLine = processedLine.Trim('"'); + Console.WriteLine($"处理行: {processedLine}"); + sb.AppendLine(processedLine); + } + + sb.AppendLine(); + sb.AppendLine(); + sb.AppendLine(); + sb.AppendLine(); + + sb.AppendLine("Characteristic,Extension,Measured_Value"); + + foreach (DataRow row in measureData.Rows) + { + var dimensionValue = row["DimensionValue"]?.ToString(); + if (dimensionValue != null && dimensionValue.Contains("1.#R")) + { + dimensionValue = ""; + } + sb.AppendFormat("{0},{1},{2}\n", + row["PointName"], row["DimensionName"], dimensionValue); + } + + File.WriteAllText(savePath, sb.ToString(), Encoding.UTF8); + } + + // 日志记录方法 + private void Trace(string msg) + { + OnLog?.Invoke(msg); + MyBase.TraceWriteLine(msg); + } + + // 打印 DataTable 对象的方法 + public static void PrintDataTable(DataTable dt) + { + if (dt == null || dt.Rows.Count == 0) + { + Console.WriteLine("[PrintDataTable] DataTable is empty or null."); + return; + } + foreach (DataColumn column in dt.Columns) + { + Console.WriteLine($"{column.ColumnName}\t"); + } + Console.WriteLine(""); + foreach (DataRow row in dt.Rows) + { + foreach (var item in row.ItemArray) + { + Console.WriteLine($"{item}\t"); + } + Console.WriteLine(""); + } + } + + // 测试方法 + public void test() + { + SQLHelper.connStr = DatabaseDfn.SqlConnectStr(); + GenCustomerReport("K0902906", "E03"); + } + } +} + public CjlrDAL _dal = new CjlrDAL(); + + //定义读取的位置 + public int readRowIndex = 2; // 默认读取第3行(从0开始计数) + + public int readColIndex = 1; // 默认读取第2列(从0开始计数) + + public event Action OnLog; // 日志事件 + public event Action OnFileParsed; // 解析完成后通知文件名 // 关键流程节点日志事件 diff --git a/Analysis/DAL/CjlrDAL.cs b/Analysis/DAL/CjlrDAL.cs index 1fe26c8..496f3dc 100644 --- a/Analysis/DAL/CjlrDAL.cs +++ b/Analysis/DAL/CjlrDAL.cs @@ -234,6 +234,9 @@ NULLIF( // check 是否有左右两侧的测量结果 public bool HasBothSidesMeasureResult(string carId) { + if (string.IsNullOrEmpty(carId)) + return false; + string sql = @" SELECT CASE WHEN COUNT(DISTINCT Remark) = 2 THEN 1 @@ -246,7 +249,10 @@ NULLIF( new SqlParameter("@CarID", carId) }; DataTable dt = SQLHelper.ExecuteQuery(sql, paras, CommandType.Text); - return dt.Rows.Count > 0 && Convert.ToInt32(dt.Rows[0]["HasBothSides"]) == 1; + // 防御性检查:空表或列不存在时返回 false,避免 Column 'HasBothSides' does not belong to table 异常 + if (dt == null || dt.Rows.Count == 0 || !dt.Columns.Contains("HasBothSides")) + return false; + return Convert.ToInt32(dt.Rows[0]["HasBothSides"]) == 1; } // 查询指定车辆ID的测量点维度数据 diff --git a/Analysis/DAL/SQLHelper.cs b/Analysis/DAL/SQLHelper.cs index bd94461..5bba3af 100644 --- a/Analysis/DAL/SQLHelper.cs +++ b/Analysis/DAL/SQLHelper.cs @@ -7,36 +7,10 @@ namespace NSAnalysis.DAL { public class SQLHelper { - private static SqlConnection conn = null; - private static SqlCommand cmd = null; - private static SqlDataReader sdr = null; public static string connStr = ""; public static int iFlag = 0; - private static SqlConnection GetConn() - { - conn = new SqlConnection(connStr); - try - { - if (conn.State == ConnectionState.Closed) - { - conn.Open(); - } - return conn; - } - catch (Exception ex) - { - if (iFlag == 0) - { - iFlag++; - MessageBox.Show("数据库打开连接失败,请检查数据库是否正确连接!原因:" + ex.ToString(), "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); - } - // 这里建议抛出异常而不是返回未打开的连接 - throw; - } - } - #region 执行不带参数的增删改SQL语句或存储过程 返回int类型 返回受影响的行数 /// @@ -47,25 +21,15 @@ namespace NSAnalysis.DAL /// 返回受影响的行数 public static int ExecuteNonQuery(string cmdText, CommandType ct) { - int res = 0; - try + using (var conn = new SqlConnection(connStr)) { - cmd = new SqlCommand(cmdText, GetConn()); - cmd.CommandType = ct; - res = cmd.ExecuteNonQuery(); //返回受影响的行数 - } - catch (Exception ex) - { - throw ex; - } - finally - { - if (conn.State == ConnectionState.Open) + conn.Open(); + using (var cmd = new SqlCommand(cmdText, conn)) { - conn.Close(); + cmd.CommandType = ct; + return cmd.ExecuteNonQuery(); } } - return res; } #endregion 执行不带参数的增删改SQL语句或存储过程 返回int类型 返回受影响的行数 @@ -80,7 +44,6 @@ namespace NSAnalysis.DAL /// 返回受影响的行数 public static int ExecuteNonQuery(string cmdText, SqlParameter[] paras, CommandType ct) { - int res = 0; using (var conn = new SqlConnection(connStr)) { conn.Open(); @@ -88,10 +51,9 @@ namespace NSAnalysis.DAL { cmd.CommandType = ct; cmd.Parameters.AddRange(paras); - res = cmd.ExecuteNonQuery(); + return cmd.ExecuteNonQuery(); } } - return res; } #endregion 执行带参数的增删改SQL语句或存储过程 返回int类型 返回受影响的行数 @@ -107,11 +69,17 @@ namespace NSAnalysis.DAL public static DataTable ExecuteQuery(string cmdText, CommandType ct) { DataTable dt = new DataTable(); - cmd = new SqlCommand(cmdText, GetConn()); - cmd.CommandType = ct; - using (sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection)) + using (var conn = new SqlConnection(connStr)) { - dt.Load(sdr); + conn.Open(); + using (var cmd = new SqlCommand(cmdText, conn)) + { + cmd.CommandType = ct; + using (var sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection)) + { + dt.Load(sdr); + } + } } return dt; } @@ -130,12 +98,18 @@ namespace NSAnalysis.DAL public static DataTable ExecuteQuery(string cmdText, SqlParameter[] paras, CommandType ct) { DataTable dt = new DataTable(); - cmd = new SqlCommand(cmdText, GetConn()); - cmd.CommandType = ct; - cmd.Parameters.AddRange(paras); - using (sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection)) + using (var conn = new SqlConnection(connStr)) { - dt.Load(sdr); + conn.Open(); + using (var cmd = new SqlCommand(cmdText, conn)) + { + cmd.CommandType = ct; + cmd.Parameters.AddRange(paras); + using (var sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection)) + { + dt.Load(sdr); + } + } } return dt; } @@ -149,11 +123,15 @@ namespace NSAnalysis.DAL /// public static DataSet ExecuteDs(String Sqlstr) { - using (SqlDataAdapter da = new SqlDataAdapter(Sqlstr, GetConn())) + using (var conn = new SqlConnection(connStr)) { - DataSet ds = new DataSet(); - da.Fill(ds); - return ds; + conn.Open(); + using (SqlDataAdapter da = new SqlDataAdapter(Sqlstr, conn)) + { + DataSet ds = new DataSet(); + da.Fill(ds); + return ds; + } } } @@ -214,28 +192,32 @@ namespace NSAnalysis.DAL public static int InsertMeasureDataToDB(DataTable InsertDT) { int iResult = 1; - using (SqlBulkCopy bulkCopy = new SqlBulkCopy(GetConn())) + using (var conn = new SqlConnection(connStr)) { - try + conn.Open(); + using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn)) { - bulkCopy.DestinationTableName = "TMeasureData";//要插入的表的表明,创造映射关系,比下面的直接写表名称 更加灵活 - bulkCopy.ColumnMappings.Add("CarID", "CarID");//映射字段名 DataTable列名 ,数据库 对应的列名 - bulkCopy.ColumnMappings.Add("CarType", "CarType");//映射字段名 DataTable列名 ,数据库 对应的列名 - bulkCopy.ColumnMappings.Add("MeasPointName", "MeasPointName"); - bulkCopy.ColumnMappings.Add("DimensionName", "DimensionName"); - bulkCopy.ColumnMappings.Add("NormalValue", "NormalValue"); - bulkCopy.ColumnMappings.Add("LowerTolVal", "LowerTolVal"); - bulkCopy.ColumnMappings.Add("UpperTolVal", "UpperTolVal"); - bulkCopy.ColumnMappings.Add("MeasureValue", "MeasureValue"); - bulkCopy.ColumnMappings.Add("MeasureItemResult", "MeasureItemResult"); - bulkCopy.ColumnMappings.Add("MeasureDate", "MeasureDate"); - bulkCopy.ColumnMappings.Add("Remark", "Remark"); - bulkCopy.WriteToServer(InsertDT); - } - catch (Exception ex) - { - MessageBox.Show("批量插入测量数据到数据库失败!原因:" + ex.ToString(), "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); - iResult = -1; + try + { + bulkCopy.DestinationTableName = "TMeasureData"; + bulkCopy.ColumnMappings.Add("CarID", "CarID"); + bulkCopy.ColumnMappings.Add("CarType", "CarType"); + bulkCopy.ColumnMappings.Add("MeasPointName", "MeasPointName"); + bulkCopy.ColumnMappings.Add("DimensionName", "DimensionName"); + bulkCopy.ColumnMappings.Add("NormalValue", "NormalValue"); + bulkCopy.ColumnMappings.Add("LowerTolVal", "LowerTolVal"); + bulkCopy.ColumnMappings.Add("UpperTolVal", "UpperTolVal"); + bulkCopy.ColumnMappings.Add("MeasureValue", "MeasureValue"); + bulkCopy.ColumnMappings.Add("MeasureItemResult", "MeasureItemResult"); + bulkCopy.ColumnMappings.Add("MeasureDate", "MeasureDate"); + bulkCopy.ColumnMappings.Add("Remark", "Remark"); + bulkCopy.WriteToServer(InsertDT); + } + catch (Exception ex) + { + MessageBox.Show("批量插入测量数据到数据库失败!原因:" + ex.ToString(), "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); + iResult = -1; + } } } return iResult; @@ -251,27 +233,26 @@ namespace NSAnalysis.DAL /// 要插入的数据表 public static void TWorkpieceListToSQLServer(DataTable InsertDT) { - using (SqlBulkCopy bulkCopy = new SqlBulkCopy(GetConn())) + using (var conn = new SqlConnection(connStr)) { - try + conn.Open(); + using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn)) { - bulkCopy.DestinationTableName = "TWorkpieceList";//要插入的表的表明,创造映射关系,比下面的直接写表名称 更加灵活 - bulkCopy.ColumnMappings.Add("WorkpieceID", "WorkpieceID");//映射字段名 DataTable列名 ,数据库 对应的列名 - bulkCopy.ColumnMappings.Add("DrawerID", "DrawerID"); - bulkCopy.ColumnMappings.Add("WorkpieceType", "WorkpieceType"); - bulkCopy.ColumnMappings.Add("TrayType", "TrayType"); - bulkCopy.ColumnMappings.Add("WorkpieceStatus", "WorkpieceStatus"); - bulkCopy.ColumnMappings.Add("WorkpiecePos", "WorkpiecePos"); - bulkCopy.WriteToServer(InsertDT); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - } - finally - { - // Close the SqlDataReader. The SqlBulkCopy object is automatically closed at - // the end of the using block. + try + { + bulkCopy.DestinationTableName = "TWorkpieceList"; + bulkCopy.ColumnMappings.Add("WorkpieceID", "WorkpieceID"); + bulkCopy.ColumnMappings.Add("DrawerID", "DrawerID"); + bulkCopy.ColumnMappings.Add("WorkpieceType", "WorkpieceType"); + bulkCopy.ColumnMappings.Add("TrayType", "TrayType"); + bulkCopy.ColumnMappings.Add("WorkpieceStatus", "WorkpieceStatus"); + bulkCopy.ColumnMappings.Add("WorkpiecePos", "WorkpiecePos"); + bulkCopy.WriteToServer(InsertDT); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } } } } @@ -287,24 +268,16 @@ namespace NSAnalysis.DAL /// 数据集 public static void SqlBulkCopyInsert(string strDBTableName, DataTable InsertDataTable) { - try + using (var conn = new SqlConnection(connStr)) { - using (SqlBulkCopy sqlRevdBulkCopy = new SqlBulkCopy(GetConn()))//引用SqlBulkCopy + conn.Open(); + using (SqlBulkCopy sqlRevdBulkCopy = new SqlBulkCopy(conn)) { - sqlRevdBulkCopy.DestinationTableName = strDBTableName;//数据库中对应的表名 - - sqlRevdBulkCopy.NotifyAfter = InsertDataTable.Rows.Count;//有几行数据 - - sqlRevdBulkCopy.WriteToServer(InsertDataTable);//数据导入数据库 - - sqlRevdBulkCopy.Close();//关闭连接 + sqlRevdBulkCopy.DestinationTableName = strDBTableName; + sqlRevdBulkCopy.NotifyAfter = InsertDataTable.Rows.Count; + sqlRevdBulkCopy.WriteToServer(InsertDataTable); } } - catch (Exception ex) - { - Console.WriteLine("数据库处理出错,SqlBulkCopyInsert,原因:" + ex.Message); - throw (ex); - } } #endregion 使用SqlBulkCopy将DataTable中的数据批量插入数据库中 diff --git a/Analysis/FormMain.cs b/Analysis/FormMain.cs index 7dc57d8..882cacd 100644 --- a/Analysis/FormMain.cs +++ b/Analysis/FormMain.cs @@ -6,6 +6,7 @@ using System.Data; using System.Drawing; using System.IO; using System.Text; +using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using Telerik.WinControls; @@ -48,6 +49,7 @@ namespace NSAnalysis { private Timer fileSortTimer = new Timer(); // 定时器,用于定时分发任务 private FileSorter fileSorter = new FileSorter(); + private int _isProcessing = 0; // 0=空闲, 1=处理中,防止定时器重入 #region 全局变量 @@ -282,7 +284,7 @@ namespace NSAnalysis #endregion 分页相关 } - private void DisplayMeasureData(string strCarID) // 其中 string strCarID 是车身ID_L 或 车身ID_R + private void DisplayMeasureData(string strCarID, string measureTime = "") // 其中 string strCarID 是车身ID_L 或 车身ID_R { try { @@ -293,27 +295,21 @@ namespace NSAnalysis return; } AnalysisResult analysis = AnalysisResult.AnalyzeMeasureData(sampleData); - //AnalysisResult.DisplayAnalysisResult(analysis); - //表格行数 int dtRowCount = analysis.TotalCount; - //超差个数 double OutCount = analysis.OutCount; - //Ok个数 double OKCount = analysis.OKCount; - //异常个数 double RejectedCount = analysis.RejectedCount; - //合格率 double FPYPercent = analysis.FPYPercent; + // 更新统计信息显示 labVIN.Text = strCarID; - labCarType.Text = ConfigDfn.strCarModel; - //labPosition_L.Text = "左侧"; + labCarType.Text = analysis.CarID; // 使用查询结果中的数据 labOKCount_L.Text = OKCount.ToString(); labNGCount_L.Text = OutCount.ToString(); labRejectCount_L.Text = RejectedCount.ToString(); labSumMeasureCount_L.Text = dtRowCount.ToString(); - labMeaTime_L.Text = ConfigDfn.strMeasureTime; + labMeaTime_L.Text = measureTime; // 使用传入的测量时间,不依赖全局变量 #region 表单区填充 @@ -359,16 +355,16 @@ namespace NSAnalysis } } - private void FileSorter_OnFileParsed(string strCarID, string Position) //形如 + private void FileSorter_OnFileParsed(string strCarID, string Position, string measureTime) //形如 { // 线程安全更新 UI if (InvokeRequired) { - Invoke(new Action(FileSorter_OnFileParsed), strCarID, Position); + Invoke(new Action(FileSorter_OnFileParsed), strCarID, Position, measureTime); return; } // 显示数据 并更新单侧汇总结果, 此时为左侧或右侧数据 - DisplayMeasureData(strCarID); + DisplayMeasureData(strCarID, measureTime); } /// 通过给定的文件流,判断文件的编码类型 @@ -682,6 +678,13 @@ namespace NSAnalysis private void FileSortTimer_Tick(object sender, EventArgs e) //分发定时器 { + // 防止上一轮未完成时重入 + if (Interlocked.CompareExchange(ref _isProcessing, 1, 0) != 0) + { + MyBase.TraceWriteLine("[FileSortTimer] 上一轮分发任务仍在执行,跳过本次触发。"); + return; + } + // 后台运行,避免阻塞UI Task.Run(() => { @@ -693,6 +696,10 @@ namespace NSAnalysis { MyBase.TraceWriteLine($"分发任务异常: {ex.Message}"); } + finally + { + Interlocked.Exchange(ref _isProcessing, 0); + } }); }