数据库520 HALCONAN安装
反射建表DB判断// 构造函数程序启动时自动运行// 参数默认数据库名 data.db数据保留30天CSV文件最大50MpublicDataRepository(stringdbFiledata.db,intretentionDays30,longmaxCsvBytes50*1024*1024){// 1. 拼接数据库路径把 data.db 放在程序根目录工控软件标准路径_dbPathPath.Combine(AppDomain.CurrentDomain.BaseDirectory,dbFile);// 2. 生成配套的CSV文件路径数据库坏了用这个_csvPathPath.ChangeExtension(_dbPath,.csv);// 专门存报警信息的CSV文件_alarmsCsvPathPath.ChangeExtension(_dbPath,.alarms.csv);// 3. 数据保留天数最小1天防止输入0/负数_retentionDaysMath.Max(1,retentionDays);// CSV文件最大大小最小1M防止文件太小崩溃_maxCsvBytesMath.Max(1024*1024,maxCsvBytes);// 核心逻辑自动检测 SQLite 驱动 try{// 反射查找 SQLite 驱动不直接引用软依赖vartType.GetType(System.Data.SQLite.SQLiteConnection, System.Data.SQLite);// 如果能找到驱动 → 启用 SQLite 数据库if(t!null){_useSqlitetrue;// 如果数据库文件不存在 → 创建一个空文件表后面自动建if(!File.Exists(_dbPath)){File.WriteAllBytes(_dbPath,newbyte[0]);}}}catch{// 找不到驱动/加载失败 → 禁用数据库只用CSV文件_useSqlitefalse;}}优先使用 SQLite 数据库存储核心varconn(IDisposable)Activator.CreateInstance(connType,$Data Source{_dbPath};Version3;);//conn 真实的、正在使用的数据库连接水管 / 通道//connType 水管图纸//Activator.CreateInstance 按照图纸做出一根真实水管// 1. 反射获取数据库连接的 Open 方法打开数据库varopenconnType.GetMethod(Open);//var 让编译器自动识别变量类型// 执行打开数据库连接//它是从数据库图纸里把「Open打开」这个方法的信息找出来。//所以 OPEN就是单独的打开方法不知道打开的内容conn是打开的内容open.Invoke(conn,null);//Invoke 就是 反射专用的 “执行方法”// 2. 反射动态创建 SQLite 命令对象不用手动引用SQLite驱动varcmdconnType.Assembly.CreateInstance(System.Data.SQLite.SQLiteCommand,false,System.Reflection.BindingFlags.CreateInstance,null,newobject[]{},null,null)asdynamic;//空的数据库执行命令工具 刚造出来、啥都没配置、啥都干不了的「毛坯工具」//叫它命令工具就是因为它的类名叫 SQLiteCommand它天生就是用来给数据库发送 SQL 命令的专用工具//false 意思类名严格区分大小写不能写错 → 必须写 SQLiteCommand不能写 sqlitecommand//BindingFlags.CreateInstance核心意思告诉电脑 → 我要创建一个新的实例造新工具 这是反射造对象必须写的固定指令//null 意思 使用系统默认的绑定器 → 不用自定义复杂规则电脑自动处理 不用管工控代码永远写 null。//new object[] { }超级重要 意思调用无参构造函数 → 造工具的时候不传任何配件// 3. 把命令绑定到数据库连接// 最后两个 null 意思语言格式、激活参数 → 系统默认完全不用管工控反射代码固定写 null。//as dynamic最后一步关键 把造出来的工具转成动态类型 → 不用强制声明类型直接点属性、调用方法 不加 as dynamic你不能写 cmd.Connection、cmd.ExecuteNonQuery()电脑不识别加了之后像正常代码一样随便用编译不报错运行自动匹配。cmd.Connection conn;// 4. SQL语句如果没有Alarms报警表就自动创建cmd.CommandTextCREATE TABLE IF NOT EXISTS Alarms( Id INTEGER PRIMARY KEY AUTOINCREMENT, // 自增ID Timestamp DATETIME, //-- 报警时间 State TEXT, // -- 报警状态 Message TEXT);;// -- 报警内容//cmd.CommandText 往工具里写具体指令cmd.ExecuteNonQuery();// 执行建表语句//cmd.ExecuteNonQuery() 让数据库执行这个指令// 5. SQL语句插入报警数据参数化写法安全不报错cmd.CommandTextINSERT INTO Alarms(Timestamp,State,Message) VALUES(ts,s,m);;// 给参数赋值把设备报警的时间、状态、信息传进去cmd.Parameters.AddWithValue(ts,alarm.Time);cmd.Parameters.AddWithValue(s,alarm.DisplayState);cmd.Parameters.AddWithValue(m,alarm.Message);//cmd.Parameters.AddWithValue 翻译给占位符填真实数据// 执行插入把数据存进数据库cmd.ExecuteNonQuery();// 6. 反射获取 Close 方法关闭数据库连接varcloseconnType.GetMethod(Close);close.Invoke(conn,null);降级方案 → 写入 CSV 文本文件try{// 加锁防止多线程同时写文件导致文件损坏lock(_fileLock){// 获取文件所在文件夹不存在就创建vardirPath.GetDirectoryName(_alarmCsvPath);if(!Directory.Exists(dir))Directory.CreateDirectory(dir);// 如果CSV文件不存在创建文件写入表头时间,状态,信息if(!File.Exists(_alarmCsvPath)){File.WriteAllText(_alarmCsvPath,Timestamp,State,Message\n,Encoding.UTF8);}// 转义双引号防止CSV格式错乱stringescStatealarm.DisplayState.Replace(\,\\);stringescMsgalarm.Message.Replace(\,\\);// 拼接一行报警数据varline$\{alarm.Time:O}\,\{escState}\,\{escMsg}\\n;// 追加写入文件File.AppendAllText(_alarmCsvPath,line,Encoding.UTF8);}}catch{}// 最后一层防护写入文件失败也不崩溃HALCON安装