CNAS取数仪器端升级
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

454 line
18KB

  1. using CnasSynchronousCommon;
  2. using CnasSynchronusClient;
  3. using CnasSynchrousModel;
  4. using Newtonsoft.Json;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Data;
  8. using System.Diagnostics;
  9. using System.IO;
  10. using System.Linq;
  11. using System.Text;
  12. using System.Timers;
  13. using System.Windows.Forms;
  14. using System.Xml.Serialization;
  15. namespace CNAS_SyncService
  16. {
  17. public class SyncServiceOperation
  18. {
  19. System.Timers.Timer timerSync;
  20. ServiceConfig config = new ServiceConfig();
  21. bool bRunComplete = true;
  22. int WaitCount = 0;
  23. string strNowDate = "";
  24. FileWatcherOperation fileWatcherOperation;
  25. public void Start()
  26. {
  27. AppLog.ServiceInfo("SyncSerivce:服务启动");
  28. //读取全局配置信息
  29. SystemFormatConfig systemFormat = FileOperation.GetSystemFormatConfigData();
  30. GlobalCommonOperation.strStartGeneralVersion = systemFormat.StartGeneralVersion;
  31. GlobalCommonOperation.strStartWebApi = systemFormat.StartWebApi;
  32. GlobalCommonOperation.strWebApiUrl = systemFormat.WebApiUrl;
  33. GlobalCommonOperation.strTargetDbType = systemFormat.TargetDBType;
  34. //读取服务配置信息
  35. config = ReadServiceConfigData();
  36. AppLog.Error("打印日志1" + config.Minutes);
  37. timerSync_Elapsed(null, null);
  38. return;
  39. if (config.Minutes != 0)
  40. {
  41. //启动文件/文件夹监控
  42. if (config.IfStartFileWatcher == "1")
  43. {
  44. fileWatcherOperation = new FileWatcherOperation(ReadSyncInstruments());
  45. fileWatcherOperation.GetFileWatcherItems();
  46. fileWatcherOperation.StartFileWatcher();
  47. }
  48. // 启动定时器
  49. timerSync = new System.Timers.Timer();
  50. timerSync.Interval = config.Minutes * 60 * 1000; //设置计时器事件间隔执行时间
  51. timerSync.Elapsed += new System.Timers.ElapsedEventHandler(timerSync_Elapsed);
  52. timerSync.Enabled = true;
  53. timerSync.AutoReset = true;
  54. }
  55. else
  56. {
  57. //写入日志
  58. AppLog.ServiceInfo("SyncSerivce:未能成功读取定时器时间,本次同步失败。");
  59. }
  60. }
  61. private void timerSync_Elapsed(object sender, ElapsedEventArgs e)
  62. {
  63. AppLog.ServiceInfo("定时器启动");
  64. //如果等待执行次数超出最大数值,则认为当前正在执行出现未知名问题,直接回收当前执行,执行下次
  65. if (WaitCount >= config.MaxWaitCount)
  66. {
  67. //回收垃圾
  68. GC.Collect();
  69. bRunComplete = true;
  70. }
  71. if (bRunComplete)
  72. {
  73. WaitCount = 0; //只要正常执行,等待标识都将恢复为0
  74. bRunComplete = false;
  75. //清理过期日志
  76. if (strNowDate != DateTime.Now.ToString("yyyyMMdd"))
  77. {
  78. AppLog.ServiceInfo("清理过期日志");
  79. strNowDate = DateTime.Now.ToString("yyyyMMdd");
  80. //删除日志文件
  81. string logDays = FileOperation.GetSystemFormatConfigData().ShowLogDays;
  82. int logday;
  83. if (int.TryParse(logDays, out logday))
  84. AppLog.DeleteLog(logday);
  85. }
  86. //执行同步程序
  87. //1.读取配置信息
  88. List<SyncInstrumentItemInfo> lstSyncInstrument = ReadSyncInstruments();
  89. //2 遍历仪器列表,逐个列表进行同步
  90. foreach (var instrumentItem in lstSyncInstrument)
  91. {
  92. //如果是文件,使用FileSystemWatcher查看文件是否发生了变化
  93. if (fileWatcherOperation != null && fileWatcherOperation.LstWatcherItems.Count > 0)
  94. {
  95. var watcherItem = fileWatcherOperation.LstWatcherItems.Where(p => p.SyncItemId == instrumentItem.GUID && p.SyncIfChanged == true).FirstOrDefault();
  96. if (watcherItem != null)
  97. {
  98. RunSyncByInstrument(instrumentItem, watcherItem);
  99. }
  100. else
  101. {
  102. AppLog.ServiceInfo("检测到文件/文件夹没有发生变化,跳过本次同步执行");
  103. }
  104. }
  105. else
  106. {
  107. RunSyncByInstrument(instrumentItem);
  108. }
  109. }
  110. bRunComplete = true;
  111. //回收垃圾
  112. GC.Collect();
  113. }
  114. else
  115. {
  116. WaitCount++;
  117. AppLog.ServiceInfo($"等待标识:{WaitCount}");
  118. }
  119. }
  120. private List<SyncInstrumentItemInfo> ReadSyncInstruments()
  121. {
  122. List<SyncInstrumentItemInfo> lstSyncInstrument = new List<SyncInstrumentItemInfo>();
  123. lstSyncInstrument = FileOperation.GetLocalSyncInStrumentData();
  124. AppLog.ServiceInfo($"读取到本地配置信息行数{lstSyncInstrument.Count}");
  125. return lstSyncInstrument;
  126. }
  127. private void RunSyncByInstrument(SyncInstrumentItemInfo syncInstrumentItem, FileWatcherItem fileWatcherItem = null)
  128. {
  129. //0.读取目标库表数据的最大时间 1.读取来源的数据 2.对读取到的数据进行逻辑处理,整理格式 3.执行同步
  130. AppLog.ServiceInfo("准备根据日期字段查询筛选");
  131. var query = syncInstrumentItem.LstSyncPramas.Where(s => s.IfDateField == true).ToList<SyncParamasInfo>();
  132. if (query.Count == 1)
  133. {
  134. string strCompareTime = "";
  135. string strDateTime = "";
  136. Dictionary<string, string> times = this.ReadSyncTime();
  137. if (true == times?.ContainsKey(syncInstrumentItem.Code))
  138. {
  139. strDateTime = $"{times[syncInstrumentItem.Code]}";
  140. }
  141. //strDateTime = "2016-07-01 00:00:00";
  142. if (strDateTime == "1899-1-1")
  143. {
  144. AppLog.ServiceInfo($"读取上次最晚执行时间失败,请检查原因。");
  145. return;
  146. }
  147. else if (strDateTime == "")
  148. {
  149. strCompareTime = Convert.ToDateTime(config.InitalDT.ToString()).ToString("yyyy-MM-dd HH:mm:ss");
  150. }
  151. else
  152. strCompareTime = Convert.ToDateTime(strDateTime).AddDays(-3).ToString("yyyy-MM-dd HH:mm:ss");
  153. AppLog.ServiceInfo($"读取上次最晚执行时间为{strCompareTime}");
  154. object[] obj = new object[]
  155. {
  156. syncInstrumentItem.LstSyncPramas[0].SourceTable,
  157. query[0].SourceField,
  158. strCompareTime
  159. };
  160. AppLog.ServiceInfo($"准备构建数据源读取工厂");
  161. InstrumentData instrumentData = InstrumentDataFact.CreateInstrumentDataSource(syncInstrumentItem.SyncInstrumentDSInfo, obj);
  162. AppLog.ServiceInfo($"构建数据源读取工厂完成,准备读取数据源");
  163. DataTable dtReadySource = instrumentData.GetInstrumentDataByDate();
  164. AppLog.ServiceInfo($"根据日期读取准备插入的来源数据,共{dtReadySource.Rows.Count}条数据");
  165. string strErrorMsg = "";
  166. RunUpLoad(syncInstrumentItem, dtReadySource, ref strErrorMsg);
  167. if (strErrorMsg != "")
  168. {
  169. //写入日志
  170. AppLog.ServiceInfo(strErrorMsg);
  171. }
  172. else
  173. {
  174. if (fileWatcherItem != null) fileWatcherItem.SyncIfChanged = false;
  175. }
  176. }
  177. else
  178. {
  179. AppLog.ServiceInfo("SyncSerivce:未能成功读取日期字段,可能不存在或存在多个日期字段,本次同步失败。");
  180. }
  181. }
  182. private void RunUpLoad(SyncInstrumentItemInfo syncInstrumentItem, DataTable dtReadySource, ref string strMsg)
  183. {
  184. //根据映射字段获取准备上传的所有数据
  185. if (dtReadySource == null || dtReadySource.Rows.Count <= 0) return;
  186. //构建准备插入的数据
  187. DataTable dtTarget = CnasDataOperationFact.CnasDataOperation().GetCNASTablesStruct(syncInstrumentItem.LstSyncPramas[0].TargetTable, syncInstrumentItem.SyncTargetDBInfo);
  188. AppLog.ServiceInfo("读取目标数据的数据结构");
  189. if (dtTarget.Columns.Count <= 0)
  190. {
  191. strMsg = "未能成功读取CNAS数据库列,请检查数据库配置。";
  192. return;
  193. }
  194. CnasInsertOperation insertOperation = new CnasInsertOperation()
  195. {
  196. syncInstrumentItem = syncInstrumentItem
  197. };
  198. AppLog.ServiceInfo("遍历所有来源数据,构造准备插入的数据");
  199. strMsg = insertOperation.CreateInputData(dtReadySource, ref dtTarget);
  200. if (strMsg != "") return;
  201. if (dtTarget.Rows.Count <= 0)
  202. {
  203. strMsg = "创建准备插入的数据行为空。";
  204. return;
  205. }
  206. AppLog.ServiceInfo("检查准备插入的数据是否合法");
  207. insertOperation.CheckInsertDataFormat(dtTarget, ref strMsg);
  208. if (strMsg != "") return;
  209. //逐行执行插入
  210. List<DataRow> lstError = new List<DataRow>();
  211. int ErrorCount = 0;
  212. int SuccessCount = 0;
  213. int OtherCount = 0;
  214. AppLog.ServiceInfo($"逐行插入目标数据,最终准备插入(更新)数据行{dtTarget.Rows.Count}");
  215. int cols = dtTarget.Columns.Count;
  216. foreach (DataRow dr in dtTarget.Rows)
  217. {
  218. if (cols >= 11 && dr[11].ToString().Length > 1)
  219. {
  220. AppLog.Error($"逐行插入目标数据,最终准备插入(更新)数据行{dr[11]}");
  221. dr[11] = kxjsf(dr[11].ToString());
  222. }
  223. if (cols >= 12 && dr[12].ToString().Length > 1)
  224. {
  225. AppLog.Error($"逐行插入目标数据,最终准备插入(更新)数据行{dr[12]}");
  226. }
  227. if (cols >= 13 && dr[13].ToString().Length > 1)
  228. {
  229. AppLog.Error($"逐行插入目标数据,最终准备插入(更新)数据行{dr[13]}");
  230. }
  231. if (cols >= 14 && dr[14].ToString().Length > 1)
  232. {
  233. AppLog.Error($"逐行插入目标数据,最终准备插入(更新)数据行{dr[14]}");
  234. }
  235. if (cols >= 15 && dr[15].ToString().Length > 1)
  236. {
  237. AppLog.Error($"逐行插入目标数据,最终准备插入(更新)数据行{dr[15]}");
  238. }
  239. if (cols >= 16 && dr[16].ToString().Length > 1)
  240. {
  241. AppLog.Error($"逐行插入目标数据,最终准备插入(更新)数据行{dr[16]}");
  242. }
  243. dr.AcceptChanges();
  244. int iReturn = CnasDataOperationFact.CnasDataOperation().InsertDataToCNASTable(GlobalCommonOperation.ConvertDataRowToTable(dr), syncInstrumentItem.SyncTargetDBInfo, syncInstrumentItem.LstSyncPramas, syncInstrumentItem.CnasInstrumentColumn, syncInstrumentItem.lstFixedValue);
  245. if (iReturn <= 0) //此时出现问题
  246. {
  247. if (iReturn == -1)
  248. {
  249. AppLog.ServiceInfo("数据库连接中断,终止本次上传。");
  250. break; //此时数据库连接中断,直接跳出循环,结束本次数据同步传输
  251. }
  252. else if (iReturn == -2) //等于-2表示插入准备更新时发现数据一致,不再执行
  253. {
  254. OtherCount++;
  255. }
  256. else
  257. {
  258. ErrorCount++;
  259. //lstError.Add(GlobalCommonOperation.ConvertDataRowToTable(dr).Rows[0]);
  260. }
  261. }
  262. else
  263. {
  264. SuccessCount++;
  265. AppLog.Info("成功插入(更新)1条数据。");
  266. }
  267. }
  268. AppLog.ServiceInfo($"上传操作完成!其中成功{SuccessCount}条,失败{ErrorCount}条,其他{OtherCount}条。............................................................................................................");
  269. WriteSyncTime(DateTime.Now, syncInstrumentItem);
  270. }
  271. private void WriteSyncTime(DateTime time, SyncInstrumentItemInfo syncInstrumentItem)
  272. {
  273. try
  274. {
  275. /* 创建文件夹 */
  276. string logDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Cache");
  277. if (!Directory.Exists(logDirectory))
  278. {
  279. Directory.CreateDirectory(logDirectory);
  280. }
  281. /* 更新时间 */
  282. string file = Path.Combine(logDirectory, $"SyncTime.bin");
  283. Dictionary<string, string> times = this.ReadSyncTime() ?? new Dictionary<string, string>();
  284. if (true == times.ContainsKey(syncInstrumentItem.Code))
  285. {
  286. times[syncInstrumentItem.Code] = time.ToString("yyyy-MM-dd HH:mm:ss");
  287. }
  288. else
  289. {
  290. times.Add(syncInstrumentItem.Code, time.ToString("yyyy-MM-dd HH:mm:ss"));
  291. }
  292. /* 写入文件 */
  293. File.WriteAllText(file, JsonConvert.SerializeObject(times, Formatting.Indented));
  294. }
  295. catch (Exception exception)
  296. {
  297. //Invoke(new MethodInvoker(delegate ()
  298. //{
  299. // this.rtxtLog.Text += $"记录同步时间出错!错误信息:{exception.Message} 日期: {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}\n";
  300. //}));
  301. }
  302. }
  303. private string kxjsf(string sss)
  304. {
  305. double sd = Convert.ToDouble(sss);
  306. //double sd = 123.123456;
  307. string temps2 = "0";
  308. string temps3 = "0";
  309. string temps4 = "0";
  310. int tempi2 = 0;
  311. int tempi3 = 0;
  312. int tempi4 = 0;
  313. if (sss.Contains('.'))
  314. {
  315. string[] s1 = sss.Split('.');
  316. if (s1[1].Length > 2)
  317. {
  318. if (s1[1].Length > 2)
  319. {
  320. temps2 = s1[1].Substring(1, 1);
  321. temps3 = s1[1].Substring(2, 1);
  322. }
  323. tempi2 = int.Parse(temps2);
  324. tempi3 = int.Parse(temps3);
  325. if (s1[1].Length > 3)
  326. {
  327. temps4 = s1[1].Substring(3, 1);
  328. }
  329. tempi4 = int.Parse(temps4);
  330. if (tempi3 > 5 || tempi3 < 5)
  331. {
  332. return sd.ToString("0.00");
  333. }
  334. else
  335. {
  336. if (tempi4 != 0)
  337. {
  338. return sd.ToString("0.00");
  339. }
  340. else
  341. {
  342. if (tempi2 == 0 || tempi2 == 2 || tempi2 == 4 || tempi2 == 6 || tempi2 == 8)
  343. {
  344. return sss.Substring(0, 5);
  345. }
  346. else
  347. {
  348. return sd.ToString("0.00");
  349. }
  350. }
  351. }
  352. }
  353. }
  354. return sss;
  355. }
  356. private ServiceConfig ReadServiceConfigData()
  357. {
  358. ServiceConfig config = new ServiceConfig();
  359. try
  360. {
  361. //读取本地文件中存储的配置信息
  362. XmlSerializer serializer = new XmlSerializer(config.GetType());
  363. FileStream stream = new FileStream(FileHelper.getBasePath() + "/DataConfig/SyncServiceData.xml", FileMode.Open);
  364. config = (ServiceConfig)serializer.Deserialize(stream);
  365. stream.Close();
  366. }
  367. catch (Exception ex)
  368. {
  369. AppLog.ServiceInfo(ex.Message);
  370. }
  371. return config;
  372. }
  373. /// <summary>
  374. ///
  375. /// </summary>
  376. private Dictionary<string, string> ReadSyncTime()
  377. {
  378. Dictionary<string, string> times = null;
  379. if (File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Cache", $"SyncTime.bin")))
  380. {
  381. try
  382. {
  383. using (StreamReader reader = new StreamReader(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Cache", $"SyncTime.bin"), Encoding.UTF8))
  384. {
  385. try
  386. {
  387. string json = reader.ReadToEnd();
  388. times = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
  389. }
  390. catch
  391. {
  392. }
  393. finally
  394. {
  395. reader.Close();
  396. reader.Dispose();
  397. }
  398. }
  399. }
  400. catch (Exception exception)
  401. {
  402. Debug.WriteLine(exception.Message);
  403. }
  404. }
  405. return times;
  406. }
  407. }
  408. }