MainDbService.cs 58 KB

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