DatabaseHelper.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. // 计划(伪代码):
  2. // 1. 在类中新增一个私有方法 `IsSupportedValue(object val)`,用于判断值是否为“常规类型”。
  3. // - 支持类型:null、string、bool、各类数值类型(包括 byte/short/int/long/float/double/decimal 等)、char、DateTime、DateTimeOffset、Guid、枚举。
  4. // - 判定可以使用 Type.IsPrimitive 并单独包含 decimal、string、DateTime 等非 primitive 类型,以及枚举判断。
  5. // 2. 在 `AddCameraRecords` 方法中,遍历 `result` 输出时:
  6. // - 对每个输出取出 name 和 value。
  7. // - 使用 `IsSupportedValue` 判断 value 类型。
  8. // - 如果不支持,跳过该输出(可写日志记录被跳过的输出名和类型)。
  9. // - 如果支持,按原逻辑构造列名并加入 `outputs` 列表。
  10. // 3. 其余逻辑保持不变:
  11. // - 若表不存在则创建,创建列时只为已收集的 `outputs` 创建列。
  12. // - 插入时为 null 写入 DBNull.Value,其他类型统一以 ToString() 写入(保留原行为,以兼容 TEXT 列)。
  13. // 4. 将伪代码以注释形式放在文件顶部,随后是修改后的完整类代码,保证格式与现有代码风格一致,能在 .NET Framework 4.8 / C# 7.3 下编译。
  14. using System;
  15. using System.Collections.Generic;
  16. using System.Data.SQLite;
  17. using System.Data;
  18. using System.Linq;
  19. using System.Text;
  20. using System.Threading.Tasks;
  21. using TeamAAS_VP;
  22. using System.IO;
  23. using TeamAAS_VP.Models;
  24. using TeamAAS_VP.Enums;
  25. using TeamAAS_VP.Core;
  26. using Cognex.VisionPro.ToolBlock;
  27. using TeamAAS_VP.Resources.Languages;
  28. namespace TeamAAS_VP.Data
  29. {
  30. public class DatabaseHelper
  31. {
  32. /// <summary>
  33. /// 初始化数据库
  34. /// </summary>
  35. /// <returns></returns>
  36. public static bool InitDatabase()
  37. {
  38. try
  39. {
  40. // 保留初始化占位(若需扩展统一建表,可在此实现)
  41. return true;
  42. }
  43. catch (Exception ex)
  44. {
  45. LogHelper.WriteLogError(Lang.数据库初始化失败, ex);
  46. return false;
  47. }
  48. }
  49. // ------------------- 新增:产品相机记录相关方法 -------------------
  50. private static string SanitizeIdentifier(string name)
  51. {
  52. if (string.IsNullOrWhiteSpace(name)) return "unnamed";
  53. var sb = new StringBuilder();
  54. foreach (var ch in name.Trim())
  55. {
  56. if (char.IsLetterOrDigit(ch) || ch == '_')
  57. sb.Append(ch);
  58. else
  59. sb.Append('_');
  60. }
  61. var s = sb.ToString();
  62. while (s.Contains("__")) s = s.Replace("__", "_");
  63. s = s.Trim('_');
  64. if (string.IsNullOrEmpty(s)) s = "unnamed";
  65. if (char.IsDigit(s[0])) s = "a" + s;
  66. if (s.Length > 64) s = s.Substring(0, 64);
  67. return s;
  68. }
  69. private static string SanitizeFileName(string name)
  70. {
  71. if (string.IsNullOrWhiteSpace(name)) return "unnamed";
  72. var invalid = Path.GetInvalidFileNameChars();
  73. var sb = new StringBuilder();
  74. foreach (var ch in name.Trim())
  75. {
  76. if (invalid.Contains(ch))
  77. sb.Append('_');
  78. else
  79. sb.Append(ch);
  80. }
  81. var s = sb.ToString();
  82. if (char.IsDigit(s[0])) s = "a" + s;
  83. s = s.Replace(" ", "_");
  84. if (s.Length > 100) s = s.Substring(0, 100);
  85. return s;
  86. }
  87. private static string GetProductDbPath(string productName)
  88. {
  89. var safeProduct = SanitizeFileName(productName);
  90. var folder = Path.Combine(FilePath.ProductsPath, productName);
  91. Directory.CreateDirectory(folder);
  92. var dbFileName = safeProduct + ".db";
  93. return Path.Combine(folder, dbFileName);
  94. }
  95. /// <summary>
  96. /// 增加一条相机拍照记录(若表或列不存在则创建)
  97. /// </summary>
  98. /// <param name="ProductName"></param>
  99. /// <param name="ProcedureName"></param>
  100. /// <param name="result"></param>
  101. public static void AddCameraRecords(string ProductName, string ProcedureName, CogToolBlockTerminalCollection result)
  102. {
  103. try
  104. {
  105. if (string.IsNullOrWhiteSpace(ProductName) || string.IsNullOrWhiteSpace(ProcedureName) || result == null)
  106. {
  107. return;
  108. }
  109. var dbpath = GetProductDbPath(ProductName);
  110. if (!File.Exists(dbpath))
  111. {
  112. SQLiteConnection.CreateFile(dbpath);
  113. }
  114. var tableName = SanitizeIdentifier(ProcedureName);
  115. var outputs = new List<(string Col, object Value)>();
  116. foreach (CogToolBlockTerminal output in result)
  117. {
  118. var col = "_" + SanitizeIdentifier(output.Name ?? "unnamed");
  119. outputs.Add((col, output.Value));
  120. }
  121. if (!IsHaveTable(tableName, dbpath))
  122. {
  123. var colsSb = new StringBuilder();
  124. colsSb.Append("_Time DATETIME");
  125. foreach (var o in outputs)
  126. {
  127. colsSb.Append($", {o.Col} TEXT");
  128. }
  129. CreateTable(tableName, $"({colsSb})", dbpath);
  130. }
  131. else
  132. {
  133. foreach (var o in outputs)
  134. {
  135. if (!IsHaveColumn(o.Col, tableName, dbpath))
  136. {
  137. AddColumn(o.Col, "TEXT", tableName, dbpath);
  138. }
  139. }
  140. if (!IsHaveColumn("_Time", tableName, dbpath))
  141. {
  142. AddColumn("_Time", "DATETIME", tableName, dbpath);
  143. }
  144. }
  145. using (var conn = new SQLiteConnection(string.Format("Data Source={0};Version=3;", dbpath)))
  146. {
  147. conn.Open();
  148. using (var cmd = new SQLiteCommand(conn))
  149. {
  150. var colNames = new List<string> { "_Time" };
  151. var paramNames = new List<string> { "@p_time" };
  152. cmd.Parameters.AddWithValue("@p_time", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
  153. for (int i = 0; i < outputs.Count; i++)
  154. {
  155. var pName = $"@p{i}";
  156. colNames.Add($"\"{outputs[i].Col}\"");
  157. var val = outputs[i].Value;
  158. if (val == null) cmd.Parameters.AddWithValue(pName, DBNull.Value);
  159. else cmd.Parameters.AddWithValue(pName, val.ToString());
  160. paramNames.Add(pName);
  161. }
  162. var sql = $"INSERT INTO \"{tableName}\" ({string.Join(", ", colNames)}) VALUES ({string.Join(", ", paramNames)});";
  163. cmd.CommandText = sql;
  164. cmd.ExecuteNonQuery();
  165. }
  166. }
  167. }
  168. catch (Exception ex)
  169. {
  170. LogHelper.WriteLogError(Lang.增加一条相机拍照记录至数据库时出错, ex);
  171. }
  172. }
  173. /// <summary>
  174. /// 根据产品名、流程名与可选时间段查询相机记录,返回 DataTable(表不存在时返回空表)
  175. /// </summary>
  176. public static DataTable GetCameraRecords(string ProductName, string ProcedureName, DateTime? from = null, DateTime? to = null)
  177. {
  178. var table = new DataTable();
  179. try
  180. {
  181. if (string.IsNullOrWhiteSpace(ProductName) || string.IsNullOrWhiteSpace(ProcedureName))
  182. return table;
  183. var dbpath = GetProductDbPath(ProductName);
  184. var tableName = SanitizeIdentifier(ProcedureName);
  185. if (!File.Exists(dbpath) || !IsHaveTable(tableName, dbpath))
  186. return table;
  187. var sb = new StringBuilder();
  188. sb.Append($"SELECT * FROM \"{tableName}\"");
  189. var parameters = new List<SQLiteParameter>();
  190. if (from.HasValue || to.HasValue)
  191. {
  192. var where = new List<string>();
  193. if (from.HasValue)
  194. {
  195. where.Add("_Time >= @from");
  196. parameters.Add(new SQLiteParameter("@from", from.Value.ToString("yyyy-MM-dd HH:mm:ss")));
  197. }
  198. if (to.HasValue)
  199. {
  200. where.Add("_Time <= @to");
  201. parameters.Add(new SQLiteParameter("@to", to.Value.ToString("yyyy-MM-dd HH:mm:ss")));
  202. }
  203. if (where.Any())
  204. {
  205. sb.Append(" WHERE " + string.Join(" AND ", where));
  206. }
  207. }
  208. sb.Append(" ORDER BY _Time DESC");
  209. using (var conn = new SQLiteConnection(string.Format("Data Source={0};Version=3;", dbpath)))
  210. {
  211. conn.Open();
  212. using (var cmd = new SQLiteCommand(sb.ToString(), conn))
  213. {
  214. if (parameters.Any()) cmd.Parameters.AddRange(parameters.ToArray());
  215. using (var da = new SQLiteDataAdapter(cmd))
  216. {
  217. da.Fill(table);
  218. }
  219. }
  220. }
  221. }
  222. catch (Exception ex)
  223. {
  224. LogHelper.WriteLogError(Lang.查询相机拍照记录时出错, ex);
  225. }
  226. return table;
  227. }
  228. /// <summary>
  229. /// 根据产品名、流程名与可选时间段查询相机记录,返回 DataTable(表不存在时返回空表)
  230. /// </summary>
  231. /// <param name="ProductName"></param>
  232. /// <param name="ProcedureName"></param>
  233. /// <param name="from"></param>
  234. /// <param name="to"></param>
  235. /// <returns></returns>
  236. public static Task<DataTable> GetCameraRecordsAsync(string ProductName, string ProcedureName, DateTime? from = null, DateTime? to = null)
  237. {
  238. return Task.Run(() => GetCameraRecords(ProductName, ProcedureName, from, to));
  239. }
  240. // ------------------- 结束新增 -------------------
  241. /// <summary>
  242. /// 检测数据库库中是否存在表
  243. /// </summary>
  244. /// <param name="TableName">表名称</param>
  245. public static bool IsHaveTable(string TableName, string dbpath)
  246. {
  247. try
  248. {
  249. using (var conn = new SQLiteConnection(string.Format("Data Source={0};Version=3;", dbpath)))
  250. {
  251. if (conn.State != ConnectionState.Open) conn.Open();
  252. string cmdStr = $"select COUNT(*) from sqlite_master where type='table' and name ='{TableName}' ";
  253. using (var cmd = new SQLiteCommand(cmdStr, conn))
  254. {
  255. return Convert.ToInt32(cmd.ExecuteScalar()) > 0;
  256. }
  257. }
  258. }
  259. catch (Exception ex)
  260. {
  261. LogHelper.WriteLogError(string.Format(Lang.检测数据库中是否存在表0时出错, TableName), ex);
  262. return false;
  263. }
  264. }
  265. /// <summary>
  266. /// 为数据创建表
  267. /// </summary>
  268. /// <param name="TableName">表的名称</param>
  269. /// <param name="column">列的名称和类型字符串(Name varchar,Team varchar, Number varchar)</param>
  270. public static bool CreateTable(string TableName, string column, string dbpath)
  271. {
  272. string query = "CREATE TABLE " + TableName + " " + column;
  273. return WriteCommandToDatabase(query, dbpath);
  274. }
  275. /// <summary>
  276. /// 为表增加列
  277. /// </summary>
  278. /// <param name="ColumnName"></param>
  279. /// <param name="ColumnType"></param>
  280. /// <param name="TableName"></param>
  281. /// <param name="dbpath"></param>
  282. public static void AddColumn(string ColumnName, string ColumnType, string TableName, string dbpath)
  283. {
  284. using (SQLiteConnection connection = new SQLiteConnection(string.Format("Data Source={0};Version=3;", dbpath)))
  285. {
  286. connection.Open();
  287. string query = $"ALTER TABLE {TableName} ADD COLUMN {ColumnName} {ColumnType}";
  288. using (SQLiteCommand command = new SQLiteCommand(query, connection))
  289. {
  290. command.ExecuteNonQuery();
  291. }
  292. }
  293. }
  294. /// <summary>
  295. /// 将命令写入数据库
  296. /// </summary>
  297. /// <param name="cmdstr"></param>
  298. public static bool WriteCommandToDatabase(string cmdstr, string dbpath)
  299. {
  300. try
  301. {
  302. using (var conn = new SQLiteConnection(string.Format("Data Source={0};Version=3;", dbpath)))
  303. {
  304. if (conn.State != ConnectionState.Open) conn.Open();
  305. using (var cmd = new SQLiteCommand(cmdstr, conn))
  306. {
  307. cmd.ExecuteNonQuery();
  308. }
  309. }
  310. return true;
  311. }
  312. catch (Exception ex)
  313. {
  314. LogHelper.WriteLogError(string.Format(Lang.写入命令至数据库时出错0,cmdstr), ex);
  315. return false;
  316. }
  317. }
  318. /// <summary>
  319. /// 检索数据
  320. /// </summary>
  321. /// <param name="strCmd"></param>
  322. /// <param name="tab"></param>
  323. /// <returns></returns>
  324. public static bool Select(string strCmd, ref DataTable tab, string dbPath)
  325. {
  326. try
  327. {
  328. using (var conn = new SQLiteConnection(string.Format("Data Source={0};Version=3;", dbPath)))
  329. {
  330. if (conn.State != ConnectionState.Open) conn.Open();
  331. using (var cmd = new SQLiteCommand(strCmd, conn))
  332. {
  333. using (var da = new SQLiteDataAdapter(cmd))
  334. {
  335. da.Fill(tab);
  336. }
  337. }
  338. }
  339. return true;
  340. }
  341. catch (Exception ex)
  342. {
  343. LogHelper.WriteLogError(Lang.检索数据库时出错, ex);
  344. return false;
  345. }
  346. }
  347. /// <summary>
  348. /// 检查是否存在包含特定字符串的记录
  349. /// </summary>
  350. /// <param name="TableName"></param>
  351. /// <param name="ColumnName"></param>
  352. /// <param name="searchString"></param>
  353. /// <returns></returns>
  354. public static bool RecordExists(string TableName, string ColumnName, string searchString, string dbPath)
  355. {
  356. try
  357. {
  358. using (var conn = new SQLiteConnection(string.Format("Data Source={0};Version=3;", dbPath)))
  359. {
  360. if (conn.State != ConnectionState.Open) conn.Open();
  361. using (var command = new SQLiteCommand($"SELECT COUNT(*) FROM {TableName} WHERE {ColumnName} LIKE @pattern", conn))
  362. {
  363. command.Parameters.AddWithValue("@pattern", $"%{searchString}%");
  364. var obj = command.ExecuteScalar();
  365. if (obj == null) return false;
  366. long count = Convert.ToInt64(obj);
  367. return count > 0;
  368. }
  369. }
  370. }
  371. catch (Exception ex)
  372. {
  373. LogHelper.WriteLogError(Lang.检查是否存在包含特定字符串的记录时出错, ex);
  374. return false;
  375. }
  376. }
  377. /// <summary>
  378. /// 检测表中是否存在列
  379. /// </summary>
  380. /// <param name="columnName"></param>
  381. /// <param name="TableName"></param>
  382. /// <param name="dbpath"></param>
  383. /// <returns></returns>
  384. public static bool IsHaveColumn(string columnName, string TableName, string dbpath)
  385. {
  386. try
  387. {
  388. using (SQLiteConnection connection = new SQLiteConnection(string.Format("Data Source={0};Version=3;", dbpath)))
  389. {
  390. connection.Open();
  391. string query = $"PRAGMA table_info({TableName});";
  392. using (SQLiteCommand command = new SQLiteCommand(query, connection))
  393. {
  394. using (SQLiteDataReader reader = command.ExecuteReader())
  395. {
  396. while (reader.Read())
  397. {
  398. string columnNameFromDB = reader["name"].ToString();
  399. if (columnNameFromDB == columnName)
  400. {
  401. return true;
  402. }
  403. }
  404. }
  405. }
  406. }
  407. return false;
  408. }
  409. catch (Exception)
  410. {
  411. return false;
  412. }
  413. }
  414. }
  415. }