MainDbService.cs 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228
  1. using Dapper;
  2. using EVCB_OCPP.Domain;
  3. using EVCB_OCPP.Domain.ConnectionFactory;
  4. using EVCB_OCPP.Domain.Models.MainDb;
  5. using EVCB_OCPP.Packet.Features;
  6. using EVCB_OCPP.Packet.Messages.Core;
  7. using EVCB_OCPP.Packet.Messages.FirmwareManagement;
  8. using EVCB_OCPP.Packet.Messages.LocalAuthListManagement;
  9. using EVCB_OCPP.Packet.Messages.RemoteTrigger;
  10. using EVCB_OCPP.Packet.Messages.Reservation;
  11. using EVCB_OCPP.Packet.Messages.Security;
  12. using EVCB_OCPP.Packet.Messages.SmartCharging;
  13. using EVCB_OCPP.WSServer.Helper;
  14. using EVCB_OCPP.WSServer.Message;
  15. using Microsoft.AspNetCore.Connections;
  16. using Microsoft.Data.SqlClient;
  17. using Microsoft.EntityFrameworkCore;
  18. using Microsoft.Extensions.Caching.Memory;
  19. using Microsoft.Extensions.Configuration;
  20. using Microsoft.Extensions.Hosting;
  21. using Microsoft.Extensions.Logging;
  22. using Newtonsoft.Json;
  23. using OCPPPackage.Profiles;
  24. using System.Data;
  25. namespace EVCB_OCPP.WSServer.Service.DbService;
  26. public interface IMainDbService
  27. {
  28. Task<string> GetMachineAuthorizationKey(string ChargeBoxId, CancellationToken token = default);
  29. Task<string> GetMachineConfiguration(string ChargeBoxId, string configName, CancellationToken token = default);
  30. Task<string> GetMachineHeartbeatInterval(string ChargeBoxId);
  31. Task<MachineAndCustomerInfo> GetMachineIdAndCustomerInfo(string ChargeBoxId, CancellationToken token = default);
  32. Task<string> GetMachineSecurityProfile(string ChargeBoxId, CancellationToken token = default);
  33. Task UpdateMachineBasicInfo(string ChargeBoxId, Machine machine);
  34. Task AddOCMF(Ocmf oCMF);
  35. ValueTask<ConnectorStatus> GetConnectorStatus(string ChargeBoxId, int ConnectorId);
  36. Task UpdateConnectorStatus(string Id, ConnectorStatus connectorStatus);
  37. ValueTask AddConnectorStatus(string ChargeBoxId, byte ConnectorId, DateTime CreatedOn, int Status,
  38. int ChargePointErrorCodeId, string ErrorInfo, string VendorId, string VendorErrorCode);
  39. Task<string> AddServerMessage(ServerMessage message);
  40. Task<string> AddServerMessage(string ChargeBoxId, string OutAction, object OutRequest, string CreatedBy = "", DateTime? CreatedOn = null, string SerialNo = "", string InMessage = "");
  41. ValueTask AddMachineError(byte ConnectorId, DateTime CreatedOn, int Status, string ChargeBoxId, int ErrorCodeId, string ErrorInfo, int PreStatus, string VendorErrorCode, string VendorId);
  42. ValueTask<Customer> GetCustomer(string id, CancellationToken token = default);
  43. ValueTask<Customer> GetCustomer(Guid id, CancellationToken token = default);
  44. Task<Guid> GetCustomerIdByChargeBoxId(string chargeboxId);
  45. Task<int?> TryGetDuplicatedTransactionId(string chargeBoxId, Guid customerId, int connectorId, DateTime timestamp);
  46. Task<int> AddNewTransactionRecord(TransactionRecord newTransaction);
  47. Task<TransactionRecord> GetTransactionForStopTransaction(int transactionId, string chargeBoxId);
  48. Task UpdateTransaction(int transactionId, int meterStop, DateTime stopTime, int stopReasonId, string stopReason, string stopIdTag, string receipt, int cost);
  49. Task<bool> UpdateHeartBeats(IEnumerable<Machine> heartBeatsData);
  50. Task<bool> UpdateHeartBeats(List<string> machineIds);
  51. Task UpdateTransactionSOC(int id, string startsoc, string stopsoc);
  52. Task UpdateMachineConnectionType(string chargeBoxId, int v);
  53. Task<string> GetMachineConnectorType(string chargeBoxId, CancellationToken token = default);
  54. Task SetMachineConnectionType(string chargeBoxId, int connectionType, CancellationToken token = default);
  55. Task UpdateServerMessageUpdateTime(int table_id);
  56. Task AddMachineConfiguration(string chargeBoxId, string key, string value, bool isReadOnly, bool isExist = true);
  57. Task UpdateMachineConfiguration(string chargeBoxId, string item, string empty, bool v, bool isExists = true);
  58. Task<List<MachineConfigurations>> GetMachineConfiguration(string chargeBoxId);
  59. Task<object> TryGetResponseFromDb(string msgId, CancellationToken token = default);
  60. }
  61. public class MainDbService : IMainDbService
  62. {
  63. public MainDbService(
  64. IDbContextFactory<MainDBContext> contextFactory,
  65. ISqlConnectionFactory<MainDBContext> sqlConnectionFactory,
  66. IMemoryCache memoryCache,
  67. IConfiguration configuration,
  68. ILoggerFactory loggerFactory,
  69. ILogger<MainDbService> logger)
  70. {
  71. this.contextFactory = contextFactory;
  72. this.sqlConnectionFactory = sqlConnectionFactory;
  73. this.memoryCache = memoryCache;
  74. this.loggerFactory = loggerFactory;
  75. this.logger = logger;
  76. var startupLimit = GetStartupLimit(configuration);
  77. //this.connectionString = configuration.GetConnectionString("MainDBContext");
  78. startupSemaphore = new(startupLimit);
  79. var opLimit = GetOpLimit(configuration);
  80. opSemaphore = new SemaphoreSlim(opLimit);
  81. InitUpdateConnectorStatusHandler();
  82. InitUpdateMachineBasicInfoHandler();
  83. InitAddServerMessageHandler();
  84. InitUpdateServerMessageUpdateOnHandler();
  85. InitGetMachineConfigurationHandler();
  86. }
  87. private const string CustomerMemCacheKeyFromat = "Customer_{0}";
  88. //private const string ChargeBoxConnectorIdMemCacheKeyFromat = "Connector_{0}{1}";
  89. private readonly IDbContextFactory<MainDBContext> contextFactory;
  90. private readonly ISqlConnectionFactory<MainDBContext> sqlConnectionFactory;
  91. private readonly IMemoryCache memoryCache;
  92. private readonly ILoggerFactory loggerFactory;
  93. private readonly ILogger<MainDbService> logger;
  94. //private string connectionString;
  95. private readonly QueueSemaphore startupSemaphore;
  96. private readonly SemaphoreSlim opSemaphore;
  97. private GroupHandler<StatusNotificationParam> statusNotificationHandler;
  98. private GroupHandler<UpdateMachineBasicInfoParam> updateMachineBasicInfoHandler;
  99. private GroupHandler<ServerMessage, string> addServerMessageHandler;
  100. private GroupHandler<int> updateServerMessageUpdateOnHandler;
  101. private GroupHandler<string, List<MachineConfigurations>> getMachineConfigurationHandler;
  102. public async Task<MachineAndCustomerInfo> GetMachineIdAndCustomerInfo(string ChargeBoxId, CancellationToken token = default)
  103. {
  104. using var semaphoreWrapper = await startupSemaphore.GetToken();
  105. using var db = await contextFactory.CreateDbContextAsync(token);
  106. var machine = await db.Machine.Where(x => x.ChargeBoxId == ChargeBoxId && x.IsDelete == false).Select(x => new { x.CustomerId, x.Id }).AsNoTracking().FirstOrDefaultAsync(token);
  107. if (machine == null)
  108. {
  109. return new MachineAndCustomerInfo(string.Empty, Guid.Empty, "Unknown");
  110. }
  111. //var customerName = await db.Customer.Where(x => x.Id == machine.CustomerId).Select(x => x.Name).FirstOrDefaultAsync();
  112. var customer = await GetCustomer(machine.CustomerId, token);
  113. var customerName = customer?.Name;
  114. return new MachineAndCustomerInfo(machine.Id, machine.CustomerId, customerName);
  115. }
  116. public Task<List<MachineConfigurations>> GetMachineConfiguration(string chargeBoxId)
  117. {
  118. return getMachineConfigurationHandler.HandleAsync(chargeBoxId);
  119. }
  120. public async Task<string> GetMachineConfiguration(string ChargeBoxId, string configName, CancellationToken token = default)
  121. {
  122. using var semaphoreWrapper = await startupSemaphore.GetToken();
  123. using var db = await contextFactory.CreateDbContextAsync(token);
  124. return await db.MachineConfigurations
  125. .Where(x => x.ChargeBoxId == ChargeBoxId && x.ConfigureName == configName)
  126. .Select(x => x.ConfigureSetting).FirstOrDefaultAsync(token);
  127. }
  128. public Task<string> GetMachineSecurityProfile(string ChargeBoxId, CancellationToken token = default)
  129. {
  130. return GetMachineConfiguration(ChargeBoxId, StandardConfiguration.SecurityProfile, token);
  131. }
  132. public Task<string> GetMachineAuthorizationKey(string ChargeBoxId, CancellationToken token = default)
  133. {
  134. return GetMachineConfiguration(ChargeBoxId, StandardConfiguration.AuthorizationKey, token);
  135. }
  136. public Task<string> GetMachineHeartbeatInterval(string ChargeBoxId)
  137. {
  138. return GetMachineConfiguration(ChargeBoxId, StandardConfiguration.HeartbeatInterval);
  139. }
  140. public Task UpdateMachineBasicInfo(string ChargeBoxId, Machine machine)
  141. {
  142. //return UpdateMachineBasicInfoEF(ChargeBoxId, machine);
  143. return updateMachineBasicInfoHandler.HandleAsync(new UpdateMachineBasicInfoParam(ChargeBoxId, machine));
  144. }
  145. public async Task AddOCMF(Ocmf oCMF)
  146. {
  147. using var db = await contextFactory.CreateDbContextAsync();
  148. await db.Ocmf.AddAsync(oCMF);
  149. await db.SaveChangesAsync();
  150. }
  151. public async ValueTask AddConnectorStatus(
  152. string ChargeBoxId, byte ConnectorId, DateTime CreatedOn, int Status,
  153. int ChargePointErrorCodeId, string ErrorInfo, string VendorId, string VendorErrorCode)
  154. {
  155. using var db = await contextFactory.CreateDbContextAsync();
  156. var _currentStatus = new ConnectorStatus()
  157. {
  158. ChargeBoxId = ChargeBoxId,
  159. ConnectorId = ConnectorId,
  160. CreatedOn = CreatedOn,
  161. Status = Status,
  162. ChargePointErrorCodeId = ChargePointErrorCodeId,
  163. ErrorInfo = ErrorInfo,
  164. VendorId = VendorId,
  165. VendorErrorCode = VendorErrorCode,
  166. Id = Guid.NewGuid().ToString()
  167. };
  168. await db.ConnectorStatus.AddAsync(_currentStatus);
  169. await db.SaveChangesAsync();
  170. //memoryCache.Set(
  171. // string.Format(ChargeBoxConnectorIdMemCacheKeyFromat, ChargeBoxId, ConnectorId)
  172. // , _currentStatus, TimeSpan.FromHours(12));
  173. }
  174. public async ValueTask<ConnectorStatus> GetConnectorStatus(string ChargeBoxId, int ConnectorId)
  175. {
  176. //var key = string.Format(ChargeBoxConnectorIdMemCacheKeyFromat, ChargeBoxId, ConnectorId);
  177. //if (memoryCache.TryGetValue<ConnectorStatus>(key, out var status))
  178. //{
  179. // return status;
  180. //}
  181. using var db = await contextFactory.CreateDbContextAsync();
  182. var statusFromDb = await db.ConnectorStatus.Where(x => x.ChargeBoxId == ChargeBoxId
  183. && x.ConnectorId == ConnectorId).AsNoTracking().FirstOrDefaultAsync();
  184. //memoryCache.Set(key, statusFromDb, TimeSpan.FromHours(12));
  185. return statusFromDb;
  186. }
  187. public async Task UpdateConnectorStatus(string Id, ConnectorStatus Status)
  188. {
  189. //await statusNotificationHandler.HandleAsync(new StatusNotificationParam(Id, Status));
  190. //await UpdateConnectorStatusEF(Id, Status);
  191. await UpdateConnectorStatusDapper(Id, Status);
  192. //var key = string.Format(ChargeBoxConnectorIdMemCacheKeyFromat, Status.ChargeBoxId, Status.ConnectorId);
  193. //memoryCache.Set(key, Status, TimeSpan.FromHours(12));
  194. return;
  195. }
  196. public Task<Guid> GetCustomerIdByChargeBoxId(string chargeboxId)
  197. {
  198. //return GetCustomerIdByChargeBoxIdEF(chargeboxId);
  199. return GetCustomerIdByChargeBoxIdDapper(chargeboxId);
  200. }
  201. public Task<int?> TryGetDuplicatedTransactionId(string chargeBoxId, Guid customerId, int connectorId, DateTime timestamp)
  202. {
  203. //return TryGetDuplicatedTransactionIdEF(chargeBoxId, customerId, connectorId, timestamp);
  204. return TryGetDuplicatedTransactionIdDapper(chargeBoxId, customerId, connectorId, timestamp);
  205. }
  206. public ValueTask AddMachineError(byte ConnectorId, DateTime CreatedOn, int Status, string ChargeBoxId,
  207. int ErrorCodeId, string ErrorInfo, int PreStatus, string VendorErrorCode, string VendorId)
  208. {
  209. //return AddMachineErrorEF(ConnectorId, CreatedOn, Status, ChargeBoxId, ErrorCodeId, ErrorInfo, PreStatus, VendorErrorCode, VendorId);
  210. return AddMachineErrorDapper(ConnectorId, CreatedOn, Status, ChargeBoxId, ErrorCodeId, ErrorInfo, PreStatus, VendorErrorCode, VendorId);
  211. }
  212. public async Task<string> AddServerMessage(string ChargeBoxId, string OutAction, object OutRequest, string CreatedBy, DateTime? CreatedOn = null, string SerialNo = "", string InMessage = "")
  213. {
  214. if (string.IsNullOrEmpty(CreatedBy))
  215. {
  216. CreatedBy = "Server";
  217. }
  218. if (string.IsNullOrEmpty(SerialNo))
  219. {
  220. SerialNo = Guid.NewGuid().ToString();
  221. }
  222. var _CreatedOn = CreatedOn ?? DateTime.UtcNow;
  223. string _OutRequest = "";
  224. if (OutRequest is not null)
  225. {
  226. _OutRequest = JsonConvert.SerializeObject(
  227. OutRequest,
  228. new JsonSerializerSettings()
  229. {
  230. NullValueHandling = NullValueHandling.Ignore,
  231. Formatting = Formatting.None
  232. });
  233. }
  234. var data = new ServerMessage()
  235. {
  236. ChargeBoxId = ChargeBoxId,
  237. CreatedBy = CreatedBy,
  238. CreatedOn = _CreatedOn,
  239. OutAction = OutAction,
  240. OutRequest = _OutRequest,
  241. SerialNo = SerialNo,
  242. InMessage = InMessage
  243. };
  244. await AddServerMessage(data);
  245. return SerialNo;
  246. }
  247. public Task<string> AddServerMessage(ServerMessage message)
  248. {
  249. //return AddServerMessageEF(message);
  250. return addServerMessageHandler.HandleAsync(message);
  251. //var id = message.SerialNo;
  252. //await AddServerMessageDapper(message);
  253. //return id;
  254. }
  255. public ValueTask<Customer> GetCustomer(string id, CancellationToken token = default)
  256. => GetCustomer(new Guid(id), token);
  257. public async ValueTask<Customer> GetCustomer(Guid id, CancellationToken token = default)
  258. {
  259. var key = string.Format(CustomerMemCacheKeyFromat, id);
  260. if (memoryCache.TryGetValue<Customer>(key, out var customer))
  261. {
  262. return customer;
  263. }
  264. Customer toReturn = null;
  265. using (var db = await contextFactory.CreateDbContextAsync(token))
  266. {
  267. toReturn = await db.Customer.FirstOrDefaultAsync(x => x.Id == id, token);
  268. }
  269. if (toReturn is not null)
  270. {
  271. memoryCache.Set(key, toReturn, TimeSpan.FromSeconds(15));
  272. }
  273. return toReturn;
  274. }
  275. public Task<int> AddNewTransactionRecord(TransactionRecord newTransaction)
  276. {
  277. //return AddNewTransactionRecordEF(newTransaction);
  278. return AddNewTransactionRecordDapper(newTransaction);
  279. }
  280. public Task<TransactionRecord> GetTransactionForStopTransaction(int transactionId, string chargeBoxId)
  281. {
  282. //return GetTransactionForStopTransactionEF(transactionId, chargeBoxId);
  283. return GetTransactionForStopTransactionDapper(transactionId, chargeBoxId);
  284. }
  285. public Task UpdateTransaction(int transactionId, int meterStop, DateTime stopTime, int stopReasonId, string stopReason, string stopIdTag, string receipt, int cost)
  286. {
  287. //return UpdateTransactionEF(transactionId, meterStop, stopTime, stopReasonId, stopReason, stopIdTag, receipt, cost);
  288. return UpdateTransactionDapper(transactionId, meterStop, stopTime, stopReasonId, stopReason, stopIdTag, receipt, cost);
  289. }
  290. public async Task UpdateTransactionSOC(int id, string startSOC, string stopSOC)
  291. {
  292. var parameters = new DynamicParameters();
  293. parameters.Add("@TransactionId", id, DbType.Int32, ParameterDirection.Input);
  294. parameters.Add("@StartSOC", startSOC, DbType.String, ParameterDirection.Input, 3);
  295. parameters.Add("@StopSOC", stopSOC, DbType.String, ParameterDirection.Input, 3);
  296. using var conn = await sqlConnectionFactory.CreateAsync();
  297. var resultCnt = await conn.ExecuteAsync("""
  298. UPDATE TransactionRecord
  299. SET StartSOC = @StartSOC, StopSOC = @StopSOC
  300. WHERE Id = @TransactionId
  301. """, parameters);
  302. if (resultCnt != 1)
  303. {
  304. throw new Exception("Update over one columes");
  305. }
  306. return;
  307. }
  308. public Task UpdateServerMessageUpdateTime(int table_id)
  309. {
  310. return updateServerMessageUpdateOnHandler.HandleAsync(table_id);
  311. }
  312. public async Task AddMachineConfiguration(string chargeBoxId, string key, string value, bool isReadOnly, bool isExists = true)
  313. {
  314. using var db = await contextFactory.CreateDbContextAsync();
  315. await db.MachineConfigurations.AddAsync(new MachineConfigurations()
  316. {
  317. ChargeBoxId = chargeBoxId,
  318. ConfigureName = key,
  319. ReadOnly = isReadOnly,
  320. ConfigureSetting = string.IsNullOrEmpty(value) ? string.Empty : value,
  321. Exists = isExists
  322. });
  323. }
  324. private async Task UpdateTransactionEF(int transactionId, int meterStop, DateTime stopTime, int stopReasonId, string stopReason, string stopIdTag, string receipt, int cost)
  325. {
  326. using var db = await contextFactory.CreateDbContextAsync();
  327. var _transaction = db.TransactionRecord.Where(x => x.Id == transactionId //&& x.ChargeBoxId == session.ChargeBoxId
  328. ).FirstOrDefault();
  329. _transaction.MeterStop = meterStop;
  330. _transaction.StopTime = stopTime;
  331. _transaction.StopReasonId = stopReasonId;
  332. _transaction.StopReason = stopReason;
  333. _transaction.StopIdTag = stopIdTag;
  334. _transaction.Receipt = receipt;
  335. _transaction.Cost = cost;
  336. //await db.SaveChangesAsync();
  337. await db.SaveChangesAsync();
  338. }
  339. public async Task UpdateMachineConfiguration(string chargeBoxId, string item, string value, bool isReadonly, bool isExists = true)
  340. {
  341. using var db = await contextFactory.CreateDbContextAsync();
  342. var config = await db.MachineConfigurations.FirstOrDefaultAsync(x => x.ChargeBoxId == chargeBoxId && x.ConfigureName == item);
  343. if (config is null)
  344. {
  345. return;
  346. }
  347. config.ConfigureSetting = value;
  348. config.ReadOnly = isReadonly;
  349. config.Exists = isExists;
  350. await db.SaveChangesAsync();
  351. }
  352. private async Task UpdateTransactionDapper(int transactionId, int meterStop, DateTime stopTime, int stopReasonId, string stopReason, string stopIdTag, string receipt, int cost)
  353. {
  354. var parameters = new DynamicParameters();
  355. parameters.Add("@TransactionId", transactionId, DbType.Int32, ParameterDirection.Input);
  356. parameters.Add("@MeterStop", meterStop, DbType.Decimal, ParameterDirection.Input, precision: 18, scale: 2);
  357. parameters.Add("@StopTime", stopTime, DbType.DateTime, ParameterDirection.Input);
  358. parameters.Add("@StopReasonId", stopReasonId, DbType.Int32, ParameterDirection.Input);
  359. parameters.Add("@StopReason", stopReason, DbType.String, ParameterDirection.Input, 60);
  360. parameters.Add("@StopIdTag", stopIdTag, DbType.String, ParameterDirection.Input, 20);
  361. parameters.Add("@Receipt", receipt, DbType.String, ParameterDirection.Input, 3000);
  362. parameters.Add("@Cost", cost, DbType.Decimal, ParameterDirection.Input, precision: 18, scale: 2);
  363. using var conn = await sqlConnectionFactory.CreateAsync();
  364. var resultCnt = await conn.ExecuteAsync("""
  365. UPDATE TransactionRecord
  366. SET MeterStop = @MeterStop, StopTime = @StopTime, StopReasonId = @StopReasonId,
  367. StopReason = @StopReason, StopIdTag = @StopIdTag, Receipt = @Receipt, Cost = @Cost
  368. WHERE Id = @TransactionId
  369. """, parameters);
  370. if (resultCnt != 1)
  371. {
  372. throw new Exception("Update over one columes");
  373. }
  374. return;
  375. }
  376. public Task<bool> UpdateHeartBeats(IEnumerable<Machine> heartBeatsData)
  377. {
  378. //return UpdateHeartBeatsEF(heartBeatsData);
  379. return UpdateHeartBeatsDapper(heartBeatsData);
  380. }
  381. public Task<bool> UpdateHeartBeats(List<string> machineIds)
  382. {
  383. return UpdateHeartBeatsDapper(machineIds);
  384. }
  385. public async Task UpdateMachineConnectionType(string chargeBoxId, int connectionType)
  386. {
  387. using var semaphoreWrapper = await startupSemaphore.GetToken();
  388. using var db = await contextFactory.CreateDbContextAsync();
  389. var machine = await db.Machine.Where(x => x.ChargeBoxId == chargeBoxId).FirstOrDefaultAsync();
  390. if (machine != null)
  391. {
  392. machine.ConnectionType = connectionType;
  393. await db.SaveChangesAsync();
  394. }
  395. }
  396. public async Task<object> TryGetResponseFromDb(string msgId, CancellationToken token = default)
  397. {
  398. var parameters = new DynamicParameters();
  399. parameters.Add("@MID", msgId, DbType.String, size: 36);
  400. parameters.Add("@MT", DateTime.UtcNow.AddSeconds(-5), DbType.DateTime);
  401. var sql = """
  402. SELECT [OutAction],[InMessage]
  403. FROM [ServerMessage]
  404. WHERE [SerialNo] = @MID AND CreatedOn > @MT
  405. """;
  406. using var conn = await sqlConnectionFactory.CreateAsync();
  407. ServerMessage item = null;
  408. item = await conn.QueryFirstOrDefaultAsync<ServerMessage>(new CommandDefinition(sql, parameters: parameters, cancellationToken: token));
  409. Actions action = Actions.None;
  410. if (item is null ||
  411. !Enum.TryParse(item.OutAction, out action))
  412. {
  413. return null;
  414. }
  415. switch (action)
  416. {
  417. case Actions.GetConfiguration:
  418. return JsonConvert.DeserializeObject<GetConfigurationConfirmation>(item.InMessage);
  419. case Actions.ChangeConfiguration:
  420. return JsonConvert.DeserializeObject<ChangeConfigurationConfirmation>(item.InMessage);
  421. case Actions.RemoteStartTransaction:
  422. return JsonConvert.DeserializeObject<RemoteStartTransactionConfirmation>(item.InMessage);
  423. case Actions.RemoteStopTransaction:
  424. return JsonConvert.DeserializeObject<RemoteStopTransactionConfirmation>(item.InMessage);
  425. case Actions.ChangeAvailability:
  426. return JsonConvert.DeserializeObject<ChangeAvailabilityConfirmation>(item.InMessage);
  427. case Actions.ClearCache:
  428. return JsonConvert.DeserializeObject<ClearCacheConfirmation>(item.InMessage);
  429. case Actions.DataTransfer:
  430. return JsonConvert.DeserializeObject<DataTransferConfirmation>(item.InMessage);
  431. case Actions.Reset:
  432. return JsonConvert.DeserializeObject<ResetConfirmation>(item.InMessage);
  433. case Actions.UnlockConnector:
  434. return JsonConvert.DeserializeObject<UnlockConnectorConfirmation>(item.InMessage);
  435. case Actions.TriggerMessage:
  436. return JsonConvert.DeserializeObject<TriggerMessageConfirmation>(item.InMessage);
  437. case Actions.GetDiagnostics:
  438. return JsonConvert.DeserializeObject<GetDiagnosticsConfirmation>(item.InMessage);
  439. case Actions.UpdateFirmware:
  440. return JsonConvert.DeserializeObject<UpdateFirmwareConfirmation>(item.InMessage);
  441. case Actions.GetLocalListVersion:
  442. return JsonConvert.DeserializeObject<GetLocalListVersionConfirmation>(item.InMessage);
  443. case Actions.SendLocalList:
  444. return JsonConvert.DeserializeObject<SendLocalListConfirmation>(item.InMessage);
  445. case Actions.SetChargingProfile:
  446. return JsonConvert.DeserializeObject<SetChargingProfileConfirmation>(item.InMessage);
  447. case Actions.ClearChargingProfile:
  448. return JsonConvert.DeserializeObject<ClearChargingProfileConfirmation>(item.InMessage);
  449. case Actions.GetCompositeSchedule:
  450. return JsonConvert.DeserializeObject<GetCompositeScheduleConfirmation>(item.InMessage);
  451. case Actions.ReserveNow:
  452. return JsonConvert.DeserializeObject<ReserveNowConfirmation>(item.InMessage);
  453. case Actions.CancelReservation:
  454. return JsonConvert.DeserializeObject<CancelReservationConfirmation>(item.InMessage);
  455. case Actions.ExtendedTriggerMessage:
  456. return JsonConvert.DeserializeObject<ExtendedTriggerMessageConfirmation>(item.InMessage);
  457. default:
  458. return null;
  459. }
  460. }
  461. private void InitUpdateConnectorStatusHandler()
  462. {
  463. if (statusNotificationHandler is not null)
  464. {
  465. throw new Exception($"{nameof(InitUpdateConnectorStatusHandler)} should only called once");
  466. }
  467. statusNotificationHandler = new GroupHandler<StatusNotificationParam>(
  468. handleFunc: BundleUpdateConnectorStatusDapper,
  469. logger: loggerFactory.CreateLogger("StatusNotificationHandler"),
  470. workerCnt: 1);
  471. }
  472. private void InitAddServerMessageHandler()
  473. {
  474. if (addServerMessageHandler is not null)
  475. {
  476. throw new Exception($"{nameof(InitAddServerMessageHandler)} should only called once");
  477. }
  478. addServerMessageHandler = new GroupHandler<ServerMessage, string>(
  479. handleFunc: BundleAddServerMessage,
  480. logger: loggerFactory.CreateLogger("AddServerMessageHandler"));
  481. }
  482. private void InitUpdateMachineBasicInfoHandler()
  483. {
  484. if (updateMachineBasicInfoHandler is not null)
  485. {
  486. throw new Exception($"{nameof(InitUpdateMachineBasicInfoHandler)} should only called once");
  487. }
  488. updateMachineBasicInfoHandler = new GroupHandler<UpdateMachineBasicInfoParam>(
  489. handleFunc: BundelUpdateMachineBasicInfo,
  490. logger: loggerFactory.CreateLogger("UpdateMachineBasicInfoHandler"),
  491. workerCnt: 1);
  492. }
  493. private void InitUpdateServerMessageUpdateOnHandler()
  494. {
  495. if (updateServerMessageUpdateOnHandler is not null)
  496. {
  497. throw new Exception($"{nameof(InitUpdateMachineBasicInfoHandler)} should only called once");
  498. }
  499. updateServerMessageUpdateOnHandler = new GroupHandler<int>(
  500. handleFunc: BundelUpdateServerMessageUpdateOn,
  501. logger: loggerFactory.CreateLogger("UpdateServerMessageUpdateOnHandler"),
  502. workerCnt: 10);
  503. }
  504. private void InitGetMachineConfigurationHandler()
  505. {
  506. if (getMachineConfigurationHandler is not null)
  507. {
  508. throw new Exception($"{nameof(InitUpdateMachineBasicInfoHandler)} should only called once");
  509. }
  510. getMachineConfigurationHandler = new GroupHandler<string, List<MachineConfigurations>>(
  511. handleFunc: BundelGetMachineConfiguration,
  512. logger: loggerFactory.CreateLogger("GetMachineConfigurationHandler"),
  513. workerCnt: 10);
  514. }
  515. private async Task UpdateMachineBasicInfoEF(string chargeBoxId, Machine machine)
  516. {
  517. using var semaphoreWrapper = await startupSemaphore.GetToken();
  518. using var db = await contextFactory.CreateDbContextAsync();
  519. var _machine = await db.Machine.FirstOrDefaultAsync(x => x.ChargeBoxId == chargeBoxId);
  520. _machine.ChargeBoxSerialNumber = machine.ChargeBoxSerialNumber;
  521. _machine.ChargePointSerialNumber = machine.ChargePointSerialNumber;
  522. _machine.ChargePointModel = machine.ChargePointModel;
  523. _machine.ChargePointVendor = machine.ChargePointVendor;
  524. _machine.FwCurrentVersion = machine.FwCurrentVersion;
  525. _machine.Iccid = machine.Iccid;
  526. _machine.Imsi = machine.Imsi;
  527. _machine.MeterSerialNumber = machine.MeterSerialNumber;
  528. _machine.MeterType = machine.MeterType;
  529. await db.SaveChangesAsync();
  530. //using var semaphoreWrapper = await startupSemaphore.GetToken();
  531. }
  532. private async Task BundelUpdateMachineBasicInfo(BundleHandlerData<UpdateMachineBasicInfoParam> bundleHandlerData)
  533. {
  534. using var db = await contextFactory.CreateDbContextAsync();
  535. using var trans = await db.Database.BeginTransactionAsync();
  536. var pams = bundleHandlerData.Datas.DistinctBy(x => x.ChargeBoxId);
  537. foreach (var pam in pams)
  538. {
  539. var _machine = db.Machine.FirstOrDefault(x => x.ChargeBoxId == pam.ChargeBoxId);
  540. _machine.ChargeBoxSerialNumber = pam.machine.ChargeBoxSerialNumber;
  541. _machine.ChargePointSerialNumber = pam.machine.ChargePointSerialNumber;
  542. _machine.ChargePointModel = pam.machine.ChargePointModel;
  543. _machine.ChargePointVendor = pam.machine.ChargePointVendor;
  544. _machine.FwCurrentVersion = pam.machine.FwCurrentVersion;
  545. _machine.Iccid = pam.machine.Iccid;
  546. _machine.Imsi = pam.machine.Imsi;
  547. _machine.MeterSerialNumber = pam.machine.MeterSerialNumber;
  548. _machine.MeterType = pam.machine.MeterType;
  549. }
  550. await db.SaveChangesAsync();
  551. await trans.CommitAsync();
  552. bundleHandlerData.CompletedDatas.AddRange(bundleHandlerData.Datas);
  553. }
  554. private async Task BundelUpdateServerMessageUpdateOn(BundleHandlerData<int> bundleHandlerData)
  555. {
  556. var ids = bundleHandlerData.Datas;
  557. var sql = """
  558. UPDATE [dbo].[ServerMessage]
  559. SET UpdatedOn = @DateTimeNow
  560. WHERE Id in @Ids
  561. """;
  562. DynamicParameters parameters = new DynamicParameters();
  563. parameters.Add("DateTimeNow", DateTime.UtcNow, DbType.DateTime);
  564. parameters.Add("Ids", ids);
  565. using SqlConnection sqlConnection = await sqlConnectionFactory.CreateAsync();
  566. var cnt = await sqlConnection.ExecuteAsync(sql, parameters);
  567. if (cnt != 0 || ids.Count == 0)
  568. {
  569. bundleHandlerData.CompletedDatas.AddRange(ids);
  570. }
  571. }
  572. private async Task BundelGetMachineConfiguration(BundleHandlerData<string, List<MachineConfigurations>> bundleHandlerData)
  573. {
  574. var chargeboxIds = bundleHandlerData.Datas;
  575. var sql = """
  576. SELECT [ChargeBoxId], [ConfigureName], [ConfigureSetting], [ReadOnly], [Exists]
  577. FROM [dbo].[MachineConfigurations]
  578. WHERE ChargeBoxId IN @ChargeBoxIds
  579. """;
  580. DynamicParameters parameters = new DynamicParameters();
  581. parameters.Add("@ChargeBoxIds", chargeboxIds, direction: ParameterDirection.Input, size: 25);
  582. using SqlConnection sqlConnection = await sqlConnectionFactory.CreateAsync();
  583. var result = await sqlConnection.QueryAsync<MachineConfigurations>(sql, parameters);
  584. var gReult = result.GroupBy(x => x.ChargeBoxId);
  585. foreach (var g in gReult)
  586. {
  587. var originKey = chargeboxIds.FirstOrDefault(x=> x.ToLower() == g.Key.ToLower());
  588. if (string.IsNullOrEmpty(originKey))
  589. {
  590. continue;
  591. }
  592. bundleHandlerData.AddCompletedData(originKey, g.ToList());
  593. }
  594. }
  595. private async Task UpdateConnectorStatusEF(string Id, ConnectorStatus Status)
  596. {
  597. using var db = await contextFactory.CreateDbContextAsync();
  598. ConnectorStatus status = new() { Id = Id };
  599. db.ChangeTracker.AutoDetectChangesEnabled = false;
  600. db.ConnectorStatus.Attach(status);
  601. status.CreatedOn = Status.CreatedOn;
  602. status.Status = Status.Status;
  603. status.ChargePointErrorCodeId = Status.ChargePointErrorCodeId;
  604. status.ErrorInfo = Status.ErrorInfo;
  605. status.VendorId = Status.VendorId;
  606. status.VendorErrorCode = Status.VendorErrorCode;
  607. db.Entry(status).Property(x => x.CreatedOn).IsModified = true;
  608. db.Entry(status).Property(x => x.Status).IsModified = true;
  609. db.Entry(status).Property(x => x.ChargePointErrorCodeId).IsModified = true;
  610. db.Entry(status).Property(x => x.ErrorInfo).IsModified = true;
  611. db.Entry(status).Property(x => x.VendorId).IsModified = true;
  612. db.Entry(status).Property(x => x.VendorErrorCode).IsModified = true;
  613. await db.SaveChangesAsync();
  614. }
  615. private async Task UpdateConnectorStatusDapper(string Id, ConnectorStatus Status)
  616. {
  617. var parameters = new DynamicParameters();
  618. parameters.Add("@Id", Id, DbType.String, ParameterDirection.Input, 36);
  619. parameters.Add("@CreatedOn", Status.CreatedOn, DbType.DateTime, ParameterDirection.Input);
  620. parameters.Add("@Status", Status.Status, DbType.Int32, ParameterDirection.Input);
  621. parameters.Add("@ChargePointErrorCodeId", Status.ChargePointErrorCodeId, DbType.Int32, ParameterDirection.Input);
  622. parameters.Add("@ErrorInfo", Status.ErrorInfo, DbType.String, ParameterDirection.Input, 50);
  623. parameters.Add("@VendorId", Status.VendorId, DbType.String, ParameterDirection.Input, 255);
  624. parameters.Add("@VendorErrorCode", Status.VendorErrorCode, DbType.String, ParameterDirection.Input, 100);
  625. using var conn = await sqlConnectionFactory.CreateAsync();
  626. await conn.ExecuteAsync("""
  627. update ConnectorStatus
  628. set
  629. CreatedOn = @CreatedOn,
  630. Status = @Status,
  631. ChargePointErrorCodeId = @ChargePointErrorCodeId,
  632. ErrorInfo = @ErrorInfo,
  633. VendorId = @VendorId,
  634. VendorErrorCode = @VendorErrorCode
  635. where Id = @Id
  636. """, parameters);
  637. }
  638. private async Task<Guid> GetCustomerIdByChargeBoxIdEF(string chargeboxId)
  639. {
  640. using var db = await contextFactory.CreateDbContextAsync();
  641. var _CustomerId = await db.Machine.Where(x => x.ChargeBoxId == chargeboxId).Select(x => x.CustomerId).FirstOrDefaultAsync();
  642. return _CustomerId;
  643. }
  644. private async Task<Guid> GetCustomerIdByChargeBoxIdDapper(string chargeboxId)
  645. {
  646. var parameters = new DynamicParameters();
  647. parameters.Add("@ChargeBoxId", chargeboxId, DbType.String, ParameterDirection.Input, 50);
  648. using var conn = await sqlConnectionFactory.CreateAsync();
  649. var _existedTx = await conn.QueryFirstOrDefaultAsync<Guid>("""
  650. select CustomerId
  651. from dbo.Machine
  652. where
  653. ChargeBoxId = @ChargeBoxId
  654. """, parameters);
  655. return _existedTx;
  656. }
  657. private async Task<int?> TryGetDuplicatedTransactionIdEF(string chargeBoxId, Guid customerId, int connectorId, DateTime timestamp)
  658. {
  659. using var db = await contextFactory.CreateDbContextAsync();
  660. var _existedTx = await db.TransactionRecord.Where(x => x.CustomerId == customerId && x.ChargeBoxId == chargeBoxId
  661. && x.ConnectorId == connectorId && x.StartTime == timestamp).Select(x => x.Id).FirstOrDefaultAsync();
  662. return _existedTx;
  663. }
  664. private async Task<int?> TryGetDuplicatedTransactionIdDapper(string chargeBoxId, Guid customerId, int connectorId, DateTime timestamp)
  665. {
  666. var parameters = new DynamicParameters();
  667. parameters.Add("@ChargeBoxId", chargeBoxId, DbType.String, ParameterDirection.Input, 50);
  668. parameters.Add("@CustomerId", customerId, DbType.Guid, ParameterDirection.Input);
  669. parameters.Add("@ConnectorId", connectorId, DbType.Int16, ParameterDirection.Input);
  670. parameters.Add("@TimeStamp", timestamp, DbType.DateTime, ParameterDirection.Input);
  671. using var conn = await sqlConnectionFactory.CreateAsync();
  672. var _existedTx = await conn.QueryFirstOrDefaultAsync<int?>("""
  673. SELECT Id
  674. FROM dbo.TransactionRecord
  675. WHERE
  676. ChargeBoxId = @ChargeBoxId and
  677. CustomerId = @CustomerId and
  678. ConnectorId = @ConnectorId and
  679. StartTime = @TimeStamp
  680. """, parameters);
  681. return _existedTx;
  682. }
  683. private async ValueTask AddMachineErrorEF(byte connectorId, DateTime createdOn, int status, string chargeBoxId, int errorCodeId, string errorInfo, int preStatus, string vendorErrorCode, string vendorId)
  684. {
  685. using var db = await contextFactory.CreateDbContextAsync();
  686. await db.MachineError.AddAsync(new MachineError()
  687. {
  688. ConnectorId = connectorId,
  689. CreatedOn = createdOn,
  690. Status = status,
  691. ChargeBoxId = chargeBoxId,
  692. ErrorCodeId = errorCodeId,
  693. ErrorInfo = errorInfo,
  694. PreStatus = preStatus,
  695. VendorErrorCode = vendorErrorCode,
  696. VendorId = vendorId
  697. });
  698. await db.SaveChangesAsync();
  699. }
  700. private async ValueTask AddMachineErrorDapper(byte connectorId, DateTime createdOn, int status, string chargeBoxId, int errorCodeId, string errorInfo, int preStatus, string vendorErrorCode, string vendorId)
  701. {
  702. var parameters = new DynamicParameters();
  703. parameters.Add("@ConnectorId", connectorId, DbType.Int16, ParameterDirection.Input);
  704. parameters.Add("@PreStatus", preStatus, DbType.Int32, ParameterDirection.Input);
  705. parameters.Add("@Status", status, DbType.Int32, ParameterDirection.Input);
  706. parameters.Add("@ErrorInfo", errorInfo, DbType.String, ParameterDirection.Input, 50);
  707. parameters.Add("@VendorId", vendorId, DbType.String, ParameterDirection.Input, 255);
  708. parameters.Add("@CreatedOn", createdOn, DbType.DateTime, ParameterDirection.Input);
  709. parameters.Add("@ErrorCodeId", errorCodeId, DbType.Int32, ParameterDirection.Input);
  710. parameters.Add("@VendorErrorCode", vendorErrorCode, DbType.String, ParameterDirection.Input, 100);
  711. parameters.Add("@ChargeBoxId", chargeBoxId, DbType.String, ParameterDirection.Input, 50);
  712. using var conn = await sqlConnectionFactory.CreateAsync();
  713. await conn.ExecuteAsync("""
  714. INSERT INTO MachineError
  715. (ConnectorId, PreStatus, Status, ErrorInfo, VendorId, CreatedOn, ErrorCodeId, VendorErrorCode, ChargeBoxId)
  716. VALUES (@ConnectorId, @PreStatus, @Status, @ErrorInfo, @VendorId, @CreatedOn, @ErrorCodeId, @VendorErrorCode, @ChargeBoxId)
  717. """, parameters);
  718. }
  719. private async Task BundleUpdateConnectorStatus(IEnumerable<StatusNotificationParam> statusNotifications)
  720. {
  721. using var db = await contextFactory.CreateDbContextAsync();
  722. using var trans = await db.Database.BeginTransactionAsync();
  723. statusNotifications = statusNotifications.OrderBy(x => x.Status.CreatedOn).DistinctBy(x => x.Id);
  724. foreach (var param in statusNotifications)
  725. {
  726. ConnectorStatus status = new() { Id = param.Id };
  727. //db.ChangeTracker.AutoDetectChangesEnabled = false;
  728. db.ConnectorStatus.Attach(status);
  729. status.CreatedOn = param.Status.CreatedOn;
  730. status.Status = param.Status.Status;
  731. status.ChargePointErrorCodeId = param.Status.ChargePointErrorCodeId;
  732. status.ErrorInfo = param.Status.ErrorInfo;
  733. status.VendorId = param.Status.VendorId;
  734. status.VendorErrorCode = param.Status.VendorErrorCode;
  735. db.Entry(status).Property(x => x.CreatedOn).IsModified = true;
  736. db.Entry(status).Property(x => x.Status).IsModified = true;
  737. db.Entry(status).Property(x => x.ChargePointErrorCodeId).IsModified = true;
  738. db.Entry(status).Property(x => x.ErrorInfo).IsModified = true;
  739. db.Entry(status).Property(x => x.VendorId).IsModified = true;
  740. db.Entry(status).Property(x => x.VendorErrorCode).IsModified = true;
  741. //await db.SaveChangesAsync();
  742. }
  743. await db.SaveChangesAsync();
  744. await trans.CommitAsync();
  745. //db.ChangeTracker.Clear();
  746. }
  747. private async Task BundleUpdateConnectorStatusDapper(BundleHandlerData<StatusNotificationParam> bundleHandlerData)
  748. {
  749. using var conn = await sqlConnectionFactory.CreateAsync();
  750. foreach (var status in bundleHandlerData.Datas)
  751. {
  752. var parameters = new DynamicParameters();
  753. parameters.Add("@Id", status.Id, DbType.String, ParameterDirection.Input, 36);
  754. parameters.Add("@CreatedOn", status.Status.CreatedOn, DbType.DateTime, ParameterDirection.Input);
  755. parameters.Add("@Status", status.Status.Status, DbType.Int32, ParameterDirection.Input);
  756. parameters.Add("@ChargePointErrorCodeId", status.Status.ChargePointErrorCodeId, DbType.Int32, ParameterDirection.Input);
  757. parameters.Add("@ErrorInfo", status.Status.ErrorInfo, DbType.String, ParameterDirection.Input, 50);
  758. parameters.Add("@VendorId", status.Status.VendorId, DbType.String, ParameterDirection.Input, 255);
  759. parameters.Add("@VendorErrorCode", status.Status.VendorErrorCode, DbType.String, ParameterDirection.Input, 100);
  760. await conn.ExecuteAsync("""
  761. update ConnectorStatus
  762. set
  763. CreatedOn = @CreatedOn,
  764. Status = @Status,
  765. ChargePointErrorCodeId = @ChargePointErrorCodeId,
  766. ErrorInfo = @ErrorInfo,
  767. VendorId = @VendorId,
  768. VendorErrorCode = @VendorErrorCode
  769. where Id = @Id
  770. """, parameters);
  771. bundleHandlerData.AddCompletedData(status);
  772. }
  773. }
  774. private async Task BundleAddServerMessage(BundleHandlerData<ServerMessage, string> bundleHandlerData)
  775. {
  776. //var sql = """
  777. // INSERT INTO [ServerMessage] ([ChargeBoxId], [CreatedBy], [CreatedOn], [InMessage], [OutAction], [OutRequest], [ReceivedOn], [SerialNo], [UpdatedOn])
  778. // OUTPUT INSERTED.Id
  779. // VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8)
  780. // """;
  781. //using var conn = await sqlConnectionFactory.CreateAsync();
  782. //foreach(var data in bundleHandlerData.Datas)
  783. //{
  784. // var dymparam = new DynamicParameters();
  785. // dymparam.Add("@p0", data.ChargeBoxId);
  786. // dymparam.Add("@p1", data.CreatedBy);
  787. // dymparam.Add("@p2", data.CreatedOn);
  788. // dymparam.Add("@p3", data.InMessage);
  789. // dymparam.Add("@p4", data.OutAction);
  790. // dymparam.Add("@p5", data.OutRequest);
  791. // dymparam.Add("@p6", data.ReceivedOn);
  792. // dymparam.Add("@p7", data.SerialNo);
  793. // dymparam.Add("@p8", data.UpdatedOn);
  794. //}
  795. using var db = await contextFactory.CreateDbContextAsync();
  796. using var trans = await db.Database.BeginTransactionAsync();
  797. foreach (var message in bundleHandlerData.Datas)
  798. {
  799. await db.ServerMessage.AddAsync(message);
  800. }
  801. await db.SaveChangesAsync();
  802. await trans.CommitAsync();
  803. bundleHandlerData.CompletedDatas.AddRange(bundleHandlerData.Datas.Select(x => new KeyValuePair<ServerMessage, string>(x, x.SerialNo)));
  804. }
  805. private async Task AddServerMessageEF(ServerMessage message)
  806. {
  807. using var db = await contextFactory.CreateDbContextAsync();
  808. using var trans = await db.Database.BeginTransactionAsync();
  809. await db.ServerMessage.AddAsync(message);
  810. await db.SaveChangesAsync();
  811. await trans.CommitAsync();
  812. //db.ChangeTracker.Clear();
  813. }
  814. private async Task AddServerMessageDapper(ServerMessage message)
  815. {
  816. var parameters = new DynamicParameters();
  817. parameters.Add("@SerialNo", message.SerialNo, DbType.String, ParameterDirection.Input, 36);
  818. parameters.Add("@OutAction", message.OutAction, DbType.String, ParameterDirection.Input, 30);
  819. parameters.Add("@OutRequest", message.OutRequest, DbType.String, ParameterDirection.Input);
  820. parameters.Add("@InMessage", message.InMessage, DbType.String, ParameterDirection.Input);
  821. parameters.Add("@CreatedOn", message.CreatedOn, DbType.DateTime, ParameterDirection.Input);
  822. parameters.Add("@CreatedBy", message.CreatedBy, DbType.String, ParameterDirection.Input, 36);
  823. parameters.Add("@ReceivedOn", message.ReceivedOn, DbType.DateTime, ParameterDirection.Input);
  824. parameters.Add("@ChargeBoxId", message.ChargeBoxId, DbType.String, ParameterDirection.Input, 30);
  825. parameters.Add("@UpdatedOn", message.UpdatedOn, DbType.DateTime, ParameterDirection.Input);
  826. using var conn = await sqlConnectionFactory.CreateAsync();
  827. var resultCnt = await conn.ExecuteAsync("""
  828. INSERT INTO ServerMessage
  829. (SerialNo, OutAction, OutRequest, InMessage, CreatedOn, CreatedBy, ReceivedOn, ChargeBoxId, UpdatedOn)
  830. VALUES (@SerialNo, @OutAction, @OutRequest, @InMessage, @CreatedOn, @CreatedBy, @ReceivedOn, @ChargeBoxId, @UpdatedOn)
  831. """, parameters);
  832. if (resultCnt != 1)
  833. {
  834. throw new Exception("Insert failed");
  835. }
  836. return;
  837. }
  838. private async Task<int> AddNewTransactionRecordEF(TransactionRecord newTransaction)
  839. {
  840. using var db = await contextFactory.CreateDbContextAsync();
  841. await db.TransactionRecord.AddAsync(newTransaction);
  842. await db.SaveChangesAsync();
  843. return newTransaction.Id;
  844. }
  845. private async Task<int> AddNewTransactionRecordDapper(TransactionRecord newTransaction)
  846. {
  847. var parameters = new DynamicParameters();
  848. parameters.Add("@ChargeBoxId", newTransaction.ChargeBoxId, DbType.String, ParameterDirection.Input, 50);
  849. parameters.Add("@ConnectorId", newTransaction.ConnectorId, DbType.Int16, ParameterDirection.Input);
  850. parameters.Add("@CreatedOn", newTransaction.CreatedOn, DbType.DateTime, ParameterDirection.Input);
  851. parameters.Add("@UpdatedOn", newTransaction.UpdatedOn, DbType.DateTime, ParameterDirection.Input);
  852. parameters.Add("@StartTransactionReportedOn", newTransaction.StartTransactionReportedOn, DbType.DateTime, ParameterDirection.Input);
  853. parameters.Add("@StopTransactionReportedOn", newTransaction.StopTransactionReportedOn, DbType.DateTime, ParameterDirection.Input);
  854. parameters.Add("@StartIdTag", newTransaction.StartIdTag, DbType.String, ParameterDirection.Input, 20);
  855. parameters.Add("@MeterStart", newTransaction.MeterStart, DbType.Decimal, ParameterDirection.Input, precision: 18, scale: 2);
  856. parameters.Add("@MeterStop", newTransaction.MeterStop, DbType.Decimal, ParameterDirection.Input, precision: 18, scale: 2);
  857. parameters.Add("@CustomerId", newTransaction.CustomerId, DbType.Guid, ParameterDirection.Input);
  858. parameters.Add("@StartTime", newTransaction.StartTime, DbType.DateTime, ParameterDirection.Input);
  859. parameters.Add("@StopTime", newTransaction.StopTime, DbType.DateTime, ParameterDirection.Input);
  860. parameters.Add("@ReservationId", newTransaction.ReservationId, DbType.Int32, ParameterDirection.Input);
  861. parameters.Add("@RetryStartTransactionTimes", newTransaction.RetryStartTransactionTimes, DbType.Int32, ParameterDirection.Input);
  862. parameters.Add("@RetryStopTransactionTimes", newTransaction.RetryStopTransactionTimes, DbType.Int32, ParameterDirection.Input);
  863. parameters.Add("@Fee", newTransaction.Fee, DbType.String, ParameterDirection.Input, 1500);
  864. using var conn = await sqlConnectionFactory.CreateAsync();
  865. var id = await conn.QuerySingleAsync<int>("""
  866. INSERT INTO TransactionRecord
  867. (ChargeBoxId, ConnectorId, CreatedOn, UpdatedOn, StartTransactionReportedOn, StopTransactionReportedOn,
  868. StartIdTag, MeterStart, MeterStop, CustomerId, StartTime, StopTime, ReservationId, RetryStartTransactionTimes, RetryStopTransactionTimes, Fee)
  869. OUTPUT INSERTED.Id
  870. VALUES (@ChargeBoxId, @ConnectorId, @CreatedOn, @UpdatedOn, @StartTransactionReportedOn, @StopTransactionReportedOn,
  871. @StartIdTag, @MeterStart, @MeterStop, @CustomerId, @StartTime, @StopTime, @ReservationId, @RetryStartTransactionTimes, @RetryStopTransactionTimes, @Fee)
  872. """, parameters);
  873. return id;
  874. }
  875. private async Task<TransactionRecord> GetTransactionForStopTransactionEF(int transactionId, string chargeBoxId)
  876. {
  877. using var db = await contextFactory.CreateDbContextAsync();
  878. return await db.TransactionRecord.Where(x => x.Id == transactionId
  879. && x.ChargeBoxId == chargeBoxId).FirstOrDefaultAsync();
  880. }
  881. private async Task<TransactionRecord> GetTransactionForStopTransactionDapper(int transactionId, string chargeBoxId)
  882. {
  883. var parameters = new DynamicParameters();
  884. parameters.Add("@TransactionId", transactionId, DbType.Int32, ParameterDirection.Input);
  885. parameters.Add("@ChargeBoxId", chargeBoxId, DbType.String, ParameterDirection.Input, 50);
  886. using var conn = await sqlConnectionFactory.CreateAsync();
  887. var record = await conn.QuerySingleAsync<TransactionRecord>("""
  888. SELECT Id, ConnectorId, MeterStop, MeterStart, StartTime, StopTime FROM TransactionRecord
  889. WHERE Id = @TransactionId and ChargeBoxId = @ChargeBoxId
  890. """, parameters);
  891. return record;
  892. }
  893. private Task BulkInsertServerMessage(IEnumerable<ServerMessage> messages)
  894. {
  895. var table = new DataTable();
  896. table.Columns.Add("ChargeBoxId");
  897. table.Columns.Add("SerialNo");
  898. table.Columns.Add("OutAction");
  899. table.Columns.Add("OutRequest");
  900. table.Columns.Add("InMessage");
  901. table.Columns.Add("CreatedOn");
  902. table.Columns.Add("CreatedBy");
  903. table.Columns.Add("UpdatedOn");
  904. table.Columns.Add("ReceivedOn");
  905. foreach (var param in messages)
  906. {
  907. var row = table.NewRow();
  908. row["ChargeBoxId"] = param.ChargeBoxId;
  909. row["SerialNo"] = param.SerialNo;
  910. row["OutAction"] = param.OutAction;
  911. row["OutRequest"] = param.OutRequest;
  912. row["InMessage"] = param.InMessage;
  913. row["CreatedOn"] = param.CreatedOn;
  914. row["CreatedBy"] = param.CreatedBy;
  915. row["UpdatedOn"] = param.UpdatedOn;
  916. row["ReceivedOn"] = param.ReceivedOn;
  917. table.Rows.Add(row);
  918. }
  919. using SqlConnection sqlConnection = sqlConnectionFactory.Create();
  920. using SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(sqlConnection);
  921. sqlBulkCopy.BatchSize = messages.Count();
  922. sqlBulkCopy.DestinationTableName = "ServerMessage";
  923. sqlBulkCopy.ColumnMappings.Add("ChargeBoxId", "ChargeBoxId");
  924. sqlBulkCopy.ColumnMappings.Add("SerialNo", "SerialNo");
  925. sqlBulkCopy.ColumnMappings.Add("OutAction", "OutAction");
  926. sqlBulkCopy.ColumnMappings.Add("OutRequest", "OutRequest");
  927. sqlBulkCopy.ColumnMappings.Add("InMessage", "InMessage");
  928. sqlBulkCopy.ColumnMappings.Add("CreatedOn", "CreatedOn");
  929. sqlBulkCopy.ColumnMappings.Add("CreatedBy", "CreatedBy");
  930. sqlBulkCopy.ColumnMappings.Add("UpdatedOn", "UpdatedOn");
  931. sqlBulkCopy.ColumnMappings.Add("ReceivedOn", "ReceivedOn");
  932. return sqlBulkCopy.WriteToServerAsync(table);
  933. }
  934. private int GetStartupLimit(IConfiguration configuration)
  935. {
  936. var limitConfig = configuration["MainDbStartupLimit"];
  937. int limit = 5;
  938. if (limitConfig != default)
  939. {
  940. int.TryParse(limitConfig, out limit);
  941. }
  942. return limit;
  943. }
  944. private int GetOpLimit(IConfiguration configuration)
  945. {
  946. var limitConfig = configuration["MainDbOpLimit"];
  947. int limit = 500;
  948. if (limitConfig != default)
  949. {
  950. int.TryParse(limitConfig, out limit);
  951. }
  952. return limit;
  953. }
  954. private async Task<bool> UpdateHeartBeatsDapper(IEnumerable<Machine> heartBeatsData)
  955. {
  956. using var conn = await sqlConnectionFactory.CreateAsync();
  957. using var trans = await conn.BeginTransactionAsync();
  958. try
  959. {
  960. foreach (var data in heartBeatsData)
  961. {
  962. var parameters = new DynamicParameters();
  963. parameters.Add("@Id", data.Id, DbType.String, ParameterDirection.Input, 36);
  964. parameters.Add("@HeartbeatUpdatedOn", data.HeartbeatUpdatedOn, DbType.DateTime, ParameterDirection.Input);
  965. parameters.Add("@ConnectionType", data.ConnectionType, DbType.Int32, ParameterDirection.Input);
  966. var resultCnt = await conn.ExecuteAsync("""
  967. UPDATE Machine
  968. SET HeartbeatUpdatedOn = @HeartbeatUpdatedOn, ConnectionType = @ConnectionType
  969. WHERE Id = @Id
  970. """, parameters, trans);
  971. if (resultCnt != 1)
  972. {
  973. throw new Exception("Update over one columes");
  974. }
  975. }
  976. await trans.CommitAsync();
  977. }
  978. catch
  979. {
  980. logger.LogCritical("HeartBeatCheckTrigger update fail, roll back");
  981. await trans.RollbackAsync();
  982. return false;
  983. }
  984. return true;
  985. }
  986. private async Task<bool> UpdateHeartBeatsDapper(List<string> machineIds)
  987. {
  988. using var conn = await sqlConnectionFactory.CreateAsync();
  989. try
  990. {
  991. var parameters = new DynamicParameters();
  992. parameters.Add("@Ids", machineIds, size: 36);
  993. parameters.Add("@HeartbeatUpdatedOn", DateTime.UtcNow, DbType.DateTime, ParameterDirection.Input);
  994. var resultCnt = await conn.ExecuteAsync("""
  995. UPDATE Machine
  996. SET HeartbeatUpdatedOn = @HeartbeatUpdatedOn
  997. WHERE Id in @Ids
  998. """, parameters);
  999. }
  1000. catch (Exception e)
  1001. {
  1002. logger.LogError(e.Message);
  1003. logger.LogCritical("HeartBeatCheckTrigger update fail");
  1004. return false;
  1005. }
  1006. return true;
  1007. }
  1008. private async Task<bool> UpdateHeartBeatsEF(IEnumerable<Machine> heartBeatsData)
  1009. {
  1010. using var db = await contextFactory.CreateDbContextAsync();
  1011. using var transaction = await db.Database.BeginTransactionAsync();
  1012. try
  1013. {
  1014. foreach (var data in heartBeatsData)
  1015. {
  1016. var machine = new Machine() { Id = data.Id };
  1017. if (machine != null)
  1018. {
  1019. db.Machine.Attach(machine);
  1020. machine.HeartbeatUpdatedOn = DateTime.UtcNow;
  1021. machine.ConnectionType = data.ConnectionType;
  1022. db.Entry(machine).Property(x => x.HeartbeatUpdatedOn).IsModified = true;
  1023. db.Entry(machine).Property(x => x.ConnectionType).IsModified = true;
  1024. }
  1025. }
  1026. await db.SaveChangesAsync();
  1027. await transaction.CommitAsync();
  1028. db.ChangeTracker.Clear();
  1029. }
  1030. catch (Exception ex)
  1031. {
  1032. logger.LogCritical(ex, "HeartBeatCheckTrigger update fail, roll back");
  1033. transaction.Rollback();
  1034. return false;
  1035. }
  1036. return true;
  1037. }
  1038. public async Task<string> GetMachineConnectorType(string chargeBoxId, CancellationToken token = default)
  1039. {
  1040. using var db = await contextFactory.CreateDbContextAsync(token);
  1041. var machine = await db.Machine.Where(x => x.ChargeBoxId == chargeBoxId).FirstOrDefaultAsync(token);
  1042. if (machine == null)
  1043. {
  1044. return null;
  1045. }
  1046. return machine.ConnectorType;
  1047. }
  1048. public async Task SetMachineConnectionType(string chargeBoxId, int v, CancellationToken token = default)
  1049. {
  1050. using var db = await contextFactory.CreateDbContextAsync(token);
  1051. var machine = await db.Machine.Where(x => x.ChargeBoxId == chargeBoxId).FirstOrDefaultAsync(token);
  1052. if (machine == null)
  1053. {
  1054. return;
  1055. }
  1056. machine.ConnectionType = v;
  1057. return;
  1058. }
  1059. }
  1060. public record MachineAndCustomerInfo(string MachineId, Guid CustomerId, string CustomerName);
  1061. public record StatusNotificationParam(string Id, ConnectorStatus Status);
  1062. public record UpdateMachineBasicInfoParam(string ChargeBoxId, Machine machine);