MainDbService.cs 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578
  1. using Azure;
  2. using Dapper;
  3. using EVCB_OCPP.Domain;
  4. using EVCB_OCPP.Domain.ConnectionFactory;
  5. using EVCB_OCPP.Domain.Models.MainDb;
  6. using EVCB_OCPP.Packet.Features;
  7. using EVCB_OCPP.Packet.Messages.Core;
  8. using EVCB_OCPP.Packet.Messages.FirmwareManagement;
  9. using EVCB_OCPP.Packet.Messages.LocalAuthListManagement;
  10. using EVCB_OCPP.Packet.Messages.RemoteTrigger;
  11. using EVCB_OCPP.Packet.Messages.Reservation;
  12. using EVCB_OCPP.Packet.Messages.Security;
  13. using EVCB_OCPP.Packet.Messages.SmartCharging;
  14. using EVCB_OCPP.Packet.Messages.SubTypes;
  15. using EVCB_OCPP.WSServer.Helper;
  16. using EVCB_OCPP.WSServer.Service.BusinessService;
  17. using Microsoft.Data.SqlClient;
  18. using Microsoft.EntityFrameworkCore;
  19. using Microsoft.Extensions.Caching.Memory;
  20. using Microsoft.Extensions.Configuration;
  21. using Microsoft.Extensions.Logging;
  22. using Newtonsoft.Json;
  23. using OCPPPackage.Profiles;
  24. using System.Data;
  25. using System.Diagnostics;
  26. namespace EVCB_OCPP.WSServer.Service.DbService;
  27. public interface IMainDbService
  28. {
  29. Task<string> GetMachineAuthorizationKey(string ChargeBoxId, CancellationToken token = default);
  30. Task<string> GetMachineConfiguration(string ChargeBoxId, string configName, CancellationToken token = default);
  31. Task<string> GetMachineHeartbeatInterval(string ChargeBoxId);
  32. Task<MachineAndCustomerInfo> GetMachineIdAndCustomerInfo(string ChargeBoxId, CancellationToken token = default);
  33. Task<string> GetMachineSecurityProfile(string ChargeBoxId, CancellationToken token = default);
  34. Task UpdateMachineBasicInfo(string ChargeBoxId, Machine machine);
  35. Task AddOCMF(Ocmf oCMF);
  36. ValueTask<ConnectorStatus> GetConnectorStatus(string ChargeBoxId, int ConnectorId);
  37. Task UpdateConnectorStatus(string Id, ConnectorStatus connectorStatus);
  38. ValueTask AddConnectorStatus(string ChargeBoxId, byte ConnectorId, DateTime CreatedOn, int Status,
  39. int ChargePointErrorCodeId, string ErrorInfo, string VendorId, string VendorErrorCode);
  40. Task<string> AddServerMessage(ServerMessage message);
  41. Task<string> AddServerMessage(string ChargeBoxId, string OutAction, object OutRequest, string CreatedBy = "", DateTime? CreatedOn = null, string SerialNo = "", string InMessage = "");
  42. ValueTask AddMachineError(byte ConnectorId, DateTime CreatedOn, int Status, string ChargeBoxId, int ErrorCodeId, string ErrorInfo, int PreStatus, string VendorErrorCode, string VendorId);
  43. ValueTask FillupFinishedTimetoMachineError(string ChargeBoxId, byte ConnectorId, DateTime FinishedOn);
  44. ValueTask<Customer> GetCustomer(string id, CancellationToken token = default);
  45. ValueTask<Customer> GetCustomer(Guid id, CancellationToken token = default);
  46. Task<Guid> GetCustomerIdByChargeBoxId(string chargeboxId);
  47. Task<int?> TryGetDuplicatedTransactionId(string chargeBoxId, Guid customerId, int connectorId, DateTime timestamp);
  48. Task<int> AddNewTransactionRecord(TransactionRecord newTransaction);
  49. Task<TransactionRecord> GetTransactionForStopTransaction(int transactionId, string chargeBoxId);
  50. Task UpdateTransaction(int transactionId, int meterStop, DateTime stopTime, int stopReasonId, string stopReason, string stopIdTag, string receipt, int cost);
  51. Task<bool> UpdateHeartBeats(IEnumerable<Machine> heartBeatsData);
  52. Task<bool> UpdateHeartBeats(List<string> machineIds);
  53. Task UpdateTransactionSOC(int id, string startsoc, string stopsoc);
  54. Task UpdateMachineConnectionType(string chargeBoxId, int v);
  55. Task<string> GetMachineConnectorType(string chargeBoxId, CancellationToken token = default);
  56. Task SetMachineConnectionType(string chargeBoxId, int connectionType, CancellationToken token = default);
  57. Task UpdateServerMessageUpdateTime(int table_id);
  58. Task AddMachineConfiguration(string chargeBoxId, string key, string value, bool isReadOnly, bool isExist = true);
  59. Task UpdateMachineConfiguration(string chargeBoxId, string item, string empty, bool isReadOnly, bool isExists = true);
  60. Task<List<MachineConfigurations>> GetMachineConfiguration(string chargeBoxId);
  61. Task<object> TryGetResponseFromDb(string msgId, CancellationToken token = default);
  62. Task InsertOrUpdateTransactionPeriodEnergy(int txId, Dictionary<string, decimal> periodEnergy);
  63. Task<Dictionary<string, decimal>> GetTransactionPeriodEnergy(int transactionId);
  64. Task<bool> UpdateCustomId(string customId, string chargeboxId);
  65. Task SetTransactionBillingDone(int txId, decimal cost, string receipt);
  66. Task SetMachineOperateRecordFinished(string requestId, string chargeBoxId, DataTransferStatus status, string data);
  67. Task RecordBoardVersions(string machineId, string data);
  68. Task<TransactionRecord> GetTransaction(int txId);
  69. Task SetPncNotifiyResult(int txid, bool isNotifySuccess, string eVCCID);
  70. Task ReportStopTx(int txid, NotifyTransactionCompletedResult reportResults);
  71. }
  72. public class MainDbService : IMainDbService
  73. {
  74. public MainDbService(
  75. IDbContextFactory<MainDBContext> contextFactory,
  76. ISqlConnectionFactory<MainDBContext> sqlConnectionFactory,
  77. IMemoryCache memoryCache,
  78. IConfiguration configuration,
  79. ILoggerFactory loggerFactory,
  80. ILogger<MainDbService> logger)
  81. {
  82. this.contextFactory = contextFactory;
  83. this.sqlConnectionFactory = sqlConnectionFactory;
  84. this.memoryCache = memoryCache;
  85. this.loggerFactory = loggerFactory;
  86. this.logger = logger;
  87. var startupLimit = GetStartupLimit(configuration);
  88. //this.connectionString = configuration.GetConnectionString("MainDBContext");
  89. startupSemaphore = new(startupLimit);
  90. var opLimit = GetOpLimit(configuration);
  91. opSemaphore = new SemaphoreSlim(opLimit);
  92. InitUpdateConnectorStatusHandler();
  93. InitUpdateMachineBasicInfoHandler();
  94. InitAddServerMessageHandler();
  95. InitUpdateServerMessageUpdateOnHandler();
  96. InitGetMachineConfigurationHandler();
  97. InitUpdateErrorFinishedOnHandler();
  98. }
  99. private const string CustomerMemCacheKeyFromat = "Customer_{0}";
  100. //private const string ChargeBoxConnectorIdMemCacheKeyFromat = "Connector_{0}{1}";
  101. private readonly IDbContextFactory<MainDBContext> contextFactory;
  102. private readonly ISqlConnectionFactory<MainDBContext> sqlConnectionFactory;
  103. private readonly IMemoryCache memoryCache;
  104. private readonly ILoggerFactory loggerFactory;
  105. private readonly ILogger<MainDbService> logger;
  106. //private string connectionString;
  107. private readonly QueueSemaphore startupSemaphore;
  108. private readonly SemaphoreSlim opSemaphore;
  109. private GroupHandler<StatusNotificationParam> statusNotificationHandler;
  110. private GroupHandler<UpdateMachineBasicInfoParam> updateMachineBasicInfoHandler;
  111. private GroupHandler<ServerMessage, string> addServerMessageHandler;
  112. private GroupHandler<int> updateServerMessageUpdateOnHandler;
  113. private GroupHandler<string, List<MachineConfigurations>> getMachineConfigurationHandler;
  114. private GroupHandler<UpdateErrofFinishedOnParam> updateErrorFinishedOnHandler;
  115. public async Task<MachineAndCustomerInfo> GetMachineIdAndCustomerInfo(string ChargeBoxId, CancellationToken token = default)
  116. {
  117. using var semaphoreWrapper = await startupSemaphore.GetToken();
  118. using var db = await contextFactory.CreateDbContextAsync(token);
  119. var machine = await db.Machine.Where(x => x.ChargeBoxId == ChargeBoxId && x.IsDelete == false).Select(x => new { x.CustomerId, x.Id }).AsNoTracking().FirstOrDefaultAsync(token);
  120. if (machine == null)
  121. {
  122. return new MachineAndCustomerInfo(string.Empty, Guid.Empty, "Unknown");
  123. }
  124. //var customerName = await db.Customer.Where(x => x.Id == machine.CustomerId).Select(x => x.Name).FirstOrDefaultAsync();
  125. var customer = await GetCustomer(machine.CustomerId, token);
  126. var customerName = customer?.Name;
  127. return new MachineAndCustomerInfo(machine.Id, machine.CustomerId, customerName);
  128. }
  129. public Task<List<MachineConfigurations>> GetMachineConfiguration(string chargeBoxId)
  130. {
  131. return getMachineConfigurationHandler.HandleAsync(chargeBoxId);
  132. }
  133. public async Task<string> GetMachineConfiguration(string ChargeBoxId, string configName, CancellationToken token = default)
  134. {
  135. using var semaphoreWrapper = await startupSemaphore.GetToken();
  136. using var db = await contextFactory.CreateDbContextAsync(token);
  137. return await db.MachineConfigurations
  138. .Where(x => x.ChargeBoxId == ChargeBoxId && x.ConfigureName == configName)
  139. .Select(x => x.ConfigureSetting).FirstOrDefaultAsync(token);
  140. }
  141. public Task<string> GetMachineSecurityProfile(string ChargeBoxId, CancellationToken token = default)
  142. {
  143. return GetMachineConfiguration(ChargeBoxId, StandardConfiguration.SecurityProfile, token);
  144. }
  145. public Task<string> GetMachineAuthorizationKey(string ChargeBoxId, CancellationToken token = default)
  146. {
  147. return GetMachineConfiguration(ChargeBoxId, StandardConfiguration.AuthorizationKey, token);
  148. }
  149. public Task<string> GetMachineHeartbeatInterval(string ChargeBoxId)
  150. {
  151. return GetMachineConfiguration(ChargeBoxId, StandardConfiguration.HeartbeatInterval);
  152. }
  153. public Task UpdateMachineBasicInfo(string ChargeBoxId, Machine machine)
  154. {
  155. //return UpdateMachineBasicInfoEF(ChargeBoxId, machine);
  156. return updateMachineBasicInfoHandler.HandleAsync(new UpdateMachineBasicInfoParam(ChargeBoxId, machine));
  157. }
  158. public async Task AddOCMF(Ocmf oCMF)
  159. {
  160. using var db = await contextFactory.CreateDbContextAsync();
  161. await db.Ocmf.AddAsync(oCMF);
  162. await db.SaveChangesAsync();
  163. }
  164. public async ValueTask AddConnectorStatus(
  165. string ChargeBoxId, byte ConnectorId, DateTime CreatedOn, int Status,
  166. int ChargePointErrorCodeId, string ErrorInfo, string VendorId, string VendorErrorCode)
  167. {
  168. using var db = await contextFactory.CreateDbContextAsync();
  169. var _currentStatus = new ConnectorStatus()
  170. {
  171. ChargeBoxId = ChargeBoxId,
  172. ConnectorId = ConnectorId,
  173. CreatedOn = CreatedOn,
  174. Status = Status,
  175. ChargePointErrorCodeId = ChargePointErrorCodeId,
  176. ErrorInfo = ErrorInfo,
  177. VendorId = VendorId,
  178. VendorErrorCode = VendorErrorCode,
  179. Id = Guid.NewGuid().ToString()
  180. };
  181. await db.ConnectorStatus.AddAsync(_currentStatus);
  182. await db.SaveChangesAsync();
  183. //memoryCache.Set(
  184. // string.Format(ChargeBoxConnectorIdMemCacheKeyFromat, ChargeBoxId, ConnectorId)
  185. // , _currentStatus, TimeSpan.FromHours(12));
  186. }
  187. public async ValueTask<ConnectorStatus> GetConnectorStatus(string ChargeBoxId, int ConnectorId)
  188. {
  189. //var key = string.Format(ChargeBoxConnectorIdMemCacheKeyFromat, ChargeBoxId, ConnectorId);
  190. //if (memoryCache.TryGetValue<ConnectorStatus>(key, out var status))
  191. //{
  192. // return status;
  193. //}
  194. using var db = await contextFactory.CreateDbContextAsync();
  195. var statusFromDb = await db.ConnectorStatus.Where(x => x.ChargeBoxId == ChargeBoxId
  196. && x.ConnectorId == ConnectorId).AsNoTracking().FirstOrDefaultAsync();
  197. //memoryCache.Set(key, statusFromDb, TimeSpan.FromHours(12));
  198. return statusFromDb;
  199. }
  200. public async Task UpdateConnectorStatus(string Id, ConnectorStatus Status)
  201. {
  202. //await statusNotificationHandler.HandleAsync(new StatusNotificationParam(Id, Status));
  203. //await UpdateConnectorStatusEF(Id, Status);
  204. await UpdateConnectorStatusDapper(Id, Status);
  205. //var key = string.Format(ChargeBoxConnectorIdMemCacheKeyFromat, Status.ChargeBoxId, Status.ConnectorId);
  206. //memoryCache.Set(key, Status, TimeSpan.FromHours(12));
  207. return;
  208. }
  209. public Task<Guid> GetCustomerIdByChargeBoxId(string chargeboxId)
  210. {
  211. //return GetCustomerIdByChargeBoxIdEF(chargeboxId);
  212. return GetCustomerIdByChargeBoxIdDapper(chargeboxId);
  213. }
  214. public Task<int?> TryGetDuplicatedTransactionId(string chargeBoxId, Guid customerId, int connectorId, DateTime timestamp)
  215. {
  216. //return TryGetDuplicatedTransactionIdEF(chargeBoxId, customerId, connectorId, timestamp);
  217. return TryGetDuplicatedTransactionIdDapper(chargeBoxId, customerId, connectorId, timestamp);
  218. }
  219. public ValueTask AddMachineError(byte ConnectorId, DateTime CreatedOn, int Status, string ChargeBoxId,
  220. int ErrorCodeId, string ErrorInfo, int PreStatus, string VendorErrorCode, string VendorId)
  221. {
  222. //return AddMachineErrorEF(ConnectorId, CreatedOn, Status, ChargeBoxId, ErrorCodeId, ErrorInfo, PreStatus, VendorErrorCode, VendorId);
  223. return AddMachineErrorDapper(ConnectorId, CreatedOn, Status, ChargeBoxId, ErrorCodeId, ErrorInfo, PreStatus, VendorErrorCode, VendorId);
  224. }
  225. public ValueTask FillupFinishedTimetoMachineError(string ChargeBoxId, byte ConnectorId, DateTime FinishedOn)
  226. {
  227. return AddFinishedTimetoMachineErrorDapper(ChargeBoxId, ConnectorId, FinishedOn);
  228. }
  229. public async Task<string> AddServerMessage(string ChargeBoxId, string OutAction, object OutRequest, string CreatedBy, DateTime? CreatedOn = null, string SerialNo = "", string InMessage = "")
  230. {
  231. if (string.IsNullOrEmpty(CreatedBy))
  232. {
  233. CreatedBy = "Server";
  234. }
  235. if (string.IsNullOrEmpty(SerialNo))
  236. {
  237. SerialNo = Guid.NewGuid().ToString();
  238. }
  239. var _CreatedOn = CreatedOn ?? DateTime.UtcNow;
  240. string _OutRequest = "";
  241. if (OutRequest is not null)
  242. {
  243. _OutRequest = JsonConvert.SerializeObject(
  244. OutRequest,
  245. new JsonSerializerSettings()
  246. {
  247. NullValueHandling = NullValueHandling.Ignore,
  248. Formatting = Formatting.None
  249. });
  250. }
  251. var data = new ServerMessage()
  252. {
  253. ChargeBoxId = ChargeBoxId,
  254. CreatedBy = CreatedBy,
  255. CreatedOn = _CreatedOn,
  256. OutAction = OutAction,
  257. OutRequest = _OutRequest,
  258. SerialNo = SerialNo,
  259. InMessage = InMessage
  260. };
  261. await AddServerMessage(data);
  262. return SerialNo;
  263. }
  264. public Task<string> AddServerMessage(ServerMessage message)
  265. {
  266. //return AddServerMessageEF(message);
  267. return addServerMessageHandler.HandleAsync(message);
  268. //var id = message.SerialNo;
  269. //await AddServerMessageDapper(message);
  270. //return id;
  271. }
  272. public ValueTask<Customer> GetCustomer(string id, CancellationToken token = default)
  273. => GetCustomer(new Guid(id), token);
  274. public async ValueTask<Customer> GetCustomer(Guid id, CancellationToken token = default)
  275. {
  276. var key = string.Format(CustomerMemCacheKeyFromat, id);
  277. if (memoryCache.TryGetValue<Customer>(key, out var customer))
  278. {
  279. return customer;
  280. }
  281. Customer toReturn = null;
  282. using (var db = await contextFactory.CreateDbContextAsync(token))
  283. {
  284. toReturn = await db.Customer.FirstOrDefaultAsync(x => x.Id == id, token);
  285. }
  286. if (toReturn is not null)
  287. {
  288. memoryCache.Set(key, toReturn, TimeSpan.FromSeconds(15));
  289. }
  290. return toReturn;
  291. }
  292. public Task<int> AddNewTransactionRecord(TransactionRecord newTransaction)
  293. {
  294. //return AddNewTransactionRecordEF(newTransaction);
  295. return AddNewTransactionRecordDapper(newTransaction);
  296. }
  297. public Task<TransactionRecord> GetTransactionForStopTransaction(int transactionId, string chargeBoxId)
  298. {
  299. //return GetTransactionForStopTransactionEF(transactionId, chargeBoxId);
  300. return GetTransactionForStopTransactionDapper(transactionId, chargeBoxId);
  301. }
  302. public Task UpdateTransaction(int transactionId, int meterStop, DateTime stopTime, int stopReasonId, string stopReason, string stopIdTag, string receipt, int cost)
  303. {
  304. //return UpdateTransactionEF(transactionId, meterStop, stopTime, stopReasonId, stopReason, stopIdTag, receipt, cost);
  305. return UpdateTransactionDapper(transactionId, meterStop, stopTime, stopReasonId, stopReason, stopIdTag, receipt, cost);
  306. }
  307. public async Task UpdateTransactionSOC(int id, string startSOC, string stopSOC)
  308. {
  309. var parameters = new DynamicParameters();
  310. parameters.Add("@TransactionId", id, DbType.Int32, ParameterDirection.Input);
  311. parameters.Add("@StartSOC", startSOC, DbType.String, ParameterDirection.Input, 3);
  312. parameters.Add("@StopSOC", stopSOC, DbType.String, ParameterDirection.Input, 3);
  313. using var conn = await sqlConnectionFactory.CreateAsync();
  314. var resultCnt = await conn.ExecuteAsync("""
  315. UPDATE TransactionRecord
  316. SET StartSOC = @StartSOC, StopSOC = @StopSOC
  317. WHERE Id = @TransactionId
  318. """, parameters);
  319. if (resultCnt != 1)
  320. {
  321. throw new Exception("Update over one columes");
  322. }
  323. return;
  324. }
  325. public Task UpdateServerMessageUpdateTime(int table_id)
  326. {
  327. return updateServerMessageUpdateOnHandler.HandleAsync(table_id);
  328. }
  329. public async Task AddMachineConfiguration(string chargeBoxId, string key, string value, bool isReadOnly, bool isExists = true)
  330. {
  331. using var db = await contextFactory.CreateDbContextAsync();
  332. await db.MachineConfigurations.AddAsync(new MachineConfigurations()
  333. {
  334. ChargeBoxId = chargeBoxId,
  335. ConfigureName = key,
  336. ReadOnly = isReadOnly,
  337. ConfigureSetting = string.IsNullOrEmpty(value) ? string.Empty : value,
  338. Exists = isExists
  339. });
  340. await db.SaveChangesAsync();
  341. }
  342. private async Task UpdateTransactionEF(int transactionId, int meterStop, DateTime stopTime, int stopReasonId, string stopReason, string stopIdTag, string receipt, int cost)
  343. {
  344. using var db = await contextFactory.CreateDbContextAsync();
  345. var _transaction = db.TransactionRecord.Where(x => x.Id == transactionId //&& x.ChargeBoxId == session.ChargeBoxId
  346. ).FirstOrDefault();
  347. _transaction.MeterStop = meterStop;
  348. _transaction.StopTime = stopTime;
  349. _transaction.StopReasonId = stopReasonId;
  350. _transaction.StopReason = stopReason;
  351. _transaction.StopIdTag = stopIdTag;
  352. _transaction.Receipt = receipt;
  353. _transaction.Cost = cost;
  354. //await db.SaveChangesAsync();
  355. await db.SaveChangesAsync();
  356. }
  357. public async Task UpdateMachineConfiguration(string chargeBoxId, string item, string value, bool isReadonly, bool isExists = true)
  358. {
  359. using var db = await contextFactory.CreateDbContextAsync();
  360. var config = await db.MachineConfigurations.FirstOrDefaultAsync(x => x.ChargeBoxId == chargeBoxId && x.ConfigureName == item);
  361. if (config is null)
  362. {
  363. return;
  364. }
  365. config.ConfigureSetting = value;
  366. config.ReadOnly = isReadonly;
  367. config.Exists = isExists;
  368. await db.SaveChangesAsync();
  369. }
  370. private async Task UpdateTransactionDapper(int transactionId, int meterStop, DateTime stopTime, int stopReasonId, string stopReason, string stopIdTag, string receipt, int cost)
  371. {
  372. var parameters = new DynamicParameters();
  373. parameters.Add("@TransactionId", transactionId, DbType.Int32, ParameterDirection.Input);
  374. parameters.Add("@MeterStop", meterStop, DbType.Decimal, ParameterDirection.Input, precision: 18, scale: 2);
  375. parameters.Add("@StopTime", stopTime, DbType.DateTime, ParameterDirection.Input);
  376. parameters.Add("@StopReasonId", stopReasonId, DbType.Int32, ParameterDirection.Input);
  377. parameters.Add("@StopReason", stopReason, DbType.String, ParameterDirection.Input, 60);
  378. parameters.Add("@StopIdTag", stopIdTag, DbType.String, ParameterDirection.Input, 20);
  379. parameters.Add("@Receipt", receipt, DbType.String, ParameterDirection.Input, 3000);
  380. parameters.Add("@Cost", cost, DbType.Decimal, ParameterDirection.Input, precision: 18, scale: 2);
  381. using var conn = await sqlConnectionFactory.CreateAsync();
  382. var resultCnt = await conn.ExecuteAsync("""
  383. UPDATE TransactionRecord
  384. SET MeterStop = @MeterStop, StopTime = @StopTime, StopReasonId = @StopReasonId,
  385. StopReason = @StopReason, StopIdTag = @StopIdTag, Receipt = @Receipt, Cost = @Cost
  386. WHERE Id = @TransactionId
  387. """, parameters);
  388. if (resultCnt != 1)
  389. {
  390. throw new Exception("Update over one columes");
  391. }
  392. return;
  393. }
  394. public Task<bool> UpdateHeartBeats(IEnumerable<Machine> heartBeatsData)
  395. {
  396. //return UpdateHeartBeatsEF(heartBeatsData);
  397. return UpdateHeartBeatsDapper(heartBeatsData);
  398. }
  399. public Task<bool> UpdateHeartBeats(List<string> machineIds)
  400. {
  401. return UpdateHeartBeatsDapper(machineIds);
  402. }
  403. public async Task<bool> UpdateCustomId(string customId,string chargeboxId)
  404. {
  405. using var conn = await sqlConnectionFactory.CreateAsync();
  406. try
  407. {
  408. var parameters = new DynamicParameters();
  409. parameters.Add("@ChargeBoxId", chargeboxId, size: 50);
  410. parameters.Add("@CustomId", customId, size: 25);
  411. var resultCnt = await conn.ExecuteAsync("""
  412. UPDATE Machine
  413. SET CustomId = @CustomId
  414. WHERE ChargeBoxId = @ChargeBoxId
  415. """, parameters);
  416. }
  417. catch (Exception e)
  418. {
  419. logger.LogError(e.Message);
  420. logger.LogCritical("UpdateCustomId update fail");
  421. return false;
  422. }
  423. return true;
  424. }
  425. public async Task UpdateMachineConnectionType(string chargeBoxId, int connectionType)
  426. {
  427. using var semaphoreWrapper = await startupSemaphore.GetToken();
  428. using var db = await contextFactory.CreateDbContextAsync();
  429. var machine = await db.Machine.Where(x => x.ChargeBoxId == chargeBoxId).FirstOrDefaultAsync();
  430. if (machine != null)
  431. {
  432. machine.ConnectionType = connectionType;
  433. await db.SaveChangesAsync();
  434. }
  435. }
  436. public async Task<object> TryGetResponseFromDb(string msgId, CancellationToken token = default)
  437. {
  438. var parameters = new DynamicParameters();
  439. parameters.Add("@MID", msgId, DbType.String, size: 36);
  440. parameters.Add("@MT", DateTime.UtcNow.AddSeconds(-5), DbType.DateTime);
  441. var sql = """
  442. SELECT [OutAction],[InMessage]
  443. FROM [ServerMessage]
  444. WHERE [SerialNo] = @MID AND CreatedOn > @MT
  445. """;
  446. using var conn = await sqlConnectionFactory.CreateAsync();
  447. ServerMessage item = null;
  448. item = await conn.QueryFirstOrDefaultAsync<ServerMessage>(new CommandDefinition(sql, parameters: parameters, cancellationToken: token));
  449. Actions action = Actions.None;
  450. if (item is null ||
  451. !Enum.TryParse(item.OutAction, out action))
  452. {
  453. return null;
  454. }
  455. switch (action)
  456. {
  457. case Actions.GetConfiguration:
  458. return JsonConvert.DeserializeObject<GetConfigurationConfirmation>(item.InMessage);
  459. case Actions.ChangeConfiguration:
  460. return JsonConvert.DeserializeObject<ChangeConfigurationConfirmation>(item.InMessage);
  461. case Actions.RemoteStartTransaction:
  462. return JsonConvert.DeserializeObject<RemoteStartTransactionConfirmation>(item.InMessage);
  463. case Actions.RemoteStopTransaction:
  464. return JsonConvert.DeserializeObject<RemoteStopTransactionConfirmation>(item.InMessage);
  465. case Actions.ChangeAvailability:
  466. return JsonConvert.DeserializeObject<ChangeAvailabilityConfirmation>(item.InMessage);
  467. case Actions.ClearCache:
  468. return JsonConvert.DeserializeObject<ClearCacheConfirmation>(item.InMessage);
  469. case Actions.DataTransfer:
  470. return JsonConvert.DeserializeObject<DataTransferConfirmation>(item.InMessage);
  471. case Actions.Reset:
  472. return JsonConvert.DeserializeObject<ResetConfirmation>(item.InMessage);
  473. case Actions.UnlockConnector:
  474. return JsonConvert.DeserializeObject<UnlockConnectorConfirmation>(item.InMessage);
  475. case Actions.TriggerMessage:
  476. return JsonConvert.DeserializeObject<TriggerMessageConfirmation>(item.InMessage);
  477. case Actions.GetDiagnostics:
  478. return JsonConvert.DeserializeObject<GetDiagnosticsConfirmation>(item.InMessage);
  479. case Actions.UpdateFirmware:
  480. return JsonConvert.DeserializeObject<UpdateFirmwareConfirmation>(item.InMessage);
  481. case Actions.GetLocalListVersion:
  482. return JsonConvert.DeserializeObject<GetLocalListVersionConfirmation>(item.InMessage);
  483. case Actions.SendLocalList:
  484. return JsonConvert.DeserializeObject<SendLocalListConfirmation>(item.InMessage);
  485. case Actions.SetChargingProfile:
  486. return JsonConvert.DeserializeObject<SetChargingProfileConfirmation>(item.InMessage);
  487. case Actions.ClearChargingProfile:
  488. return JsonConvert.DeserializeObject<ClearChargingProfileConfirmation>(item.InMessage);
  489. case Actions.GetCompositeSchedule:
  490. return JsonConvert.DeserializeObject<GetCompositeScheduleConfirmation>(item.InMessage);
  491. case Actions.ReserveNow:
  492. return JsonConvert.DeserializeObject<ReserveNowConfirmation>(item.InMessage);
  493. case Actions.CancelReservation:
  494. return JsonConvert.DeserializeObject<CancelReservationConfirmation>(item.InMessage);
  495. case Actions.ExtendedTriggerMessage:
  496. return JsonConvert.DeserializeObject<ExtendedTriggerMessageConfirmation>(item.InMessage);
  497. default:
  498. return null;
  499. }
  500. }
  501. public async Task SetTransactionBillingDone(int txId, decimal cost, string receipt)
  502. {
  503. using var db = await contextFactory.CreateDbContextAsync();
  504. TransactionRecord transaction = await db.TransactionRecord.Where(x => x.Id == txId).FirstOrDefaultAsync();
  505. if (transaction is null)
  506. {
  507. logger.LogTrace("Tx is empty");
  508. return;
  509. }
  510. transaction.Cost = cost;
  511. transaction.Receipt = receipt;
  512. transaction.BillingDone = true;
  513. db.ChangeTracker.AutoDetectChangesEnabled = false;
  514. //db.Configuration.ValidateOnSaveEnabled = false;
  515. db.TransactionRecord.Attach(transaction);
  516. db.Entry(transaction).Property(x => x.Cost).IsModified = true;
  517. db.Entry(transaction).Property(x => x.Receipt).IsModified = true;
  518. db.Entry(transaction).Property(x => x.BillingDone).IsModified = true;
  519. await db.SaveChangesAsync();
  520. }
  521. public async Task SetMachineOperateRecordFinished(string requestId, string chargeBoxId, DataTransferStatus status, string data)
  522. {
  523. using var db = await contextFactory.CreateDbContextAsync();
  524. var operation = await db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
  525. x.ChargeBoxId == chargeBoxId && x.Status == 0).FirstOrDefaultAsync();
  526. if (operation != null)
  527. {
  528. operation.FinishedOn = DateTime.UtcNow;
  529. operation.Status = 1;//電樁有回覆
  530. operation.EvseStatus = (int)status;
  531. operation.EvseValue = string.IsNullOrEmpty(data) ? "" : data;
  532. await db.SaveChangesAsync();
  533. }
  534. }
  535. public async Task RecordBoardVersions(string machineId, string data)
  536. {
  537. using var db = await contextFactory.CreateDbContextAsync();
  538. var machine = new Machine() { Id = machineId };
  539. if (machine != null)
  540. {
  541. db.ChangeTracker.AutoDetectChangesEnabled = false;
  542. //db.Configuration.ValidateOnSaveEnabled = false;
  543. db.Machine.Attach(machine);
  544. machine.BoardVersions = data;
  545. db.Entry(machine).Property(x => x.BoardVersions).IsModified = true;
  546. await db.SaveChangesAsync();
  547. }
  548. }
  549. public async Task<TransactionRecord> GetTransaction(int txId)
  550. {
  551. using var db = await contextFactory.CreateDbContextAsync();
  552. TransactionRecord feedto = await db.TransactionRecord.Where(x => x.Id == txId).FirstOrDefaultAsync();
  553. return feedto;
  554. }
  555. public async Task SetPncNotifiyResult(int txid, bool isNotifySuccess, string eVCCID)
  556. {
  557. using var db = await contextFactory.CreateDbContextAsync();
  558. var pnc_info = db.TransactionRecord.Where(x => x.Id == txid).FirstOrDefault();
  559. pnc_info.NotifyPnC = isNotifySuccess;
  560. pnc_info.Evccid = eVCCID;
  561. db.ChangeTracker.AutoDetectChangesEnabled = false;
  562. db.TransactionRecord.Attach(pnc_info);
  563. db.Entry(pnc_info).Property(x => x.Evccid).IsModified = true;
  564. db.Entry(pnc_info).Property(x => x.NotifyPnC).IsModified = true;
  565. await db.SaveChangesAsync();
  566. }
  567. public async Task ReportStopTx(int txid, NotifyTransactionCompletedResult reportResults)
  568. {
  569. using var dbConn = await sqlConnectionFactory.CreateAsync();
  570. var cmd = """
  571. UPDATE [dbo].[TransactionRecord]
  572. SET StopTransactionReportedOn=@StopTransactionReportedOn, ErrorMsg=@ErrorMsg
  573. WHERE Id=@Id
  574. """;
  575. var parameters = new DynamicParameters();
  576. parameters.Add("@Id", txid, DbType.Int32, ParameterDirection.Input);
  577. parameters.Add("@StopTransactionReportedOn", DateTime.UtcNow, DbType.DateTime, ParameterDirection.Input);
  578. parameters.Add("@ErrorMsg", reportResults.ErrorMsg, DbType.String, ParameterDirection.Input, -1);
  579. await dbConn.ExecuteAsync(cmd, parameters);
  580. }
  581. private void InitUpdateConnectorStatusHandler()
  582. {
  583. if (statusNotificationHandler is not null)
  584. {
  585. throw new Exception($"{nameof(InitUpdateConnectorStatusHandler)} should only called once");
  586. }
  587. statusNotificationHandler = new GroupHandler<StatusNotificationParam>(
  588. handleFunc: BundleUpdateConnectorStatusDapper,
  589. logger: loggerFactory.CreateLogger("StatusNotificationHandler"),
  590. workerCnt: 1);
  591. }
  592. private void InitAddServerMessageHandler()
  593. {
  594. if (addServerMessageHandler is not null)
  595. {
  596. throw new Exception($"{nameof(InitAddServerMessageHandler)} should only called once");
  597. }
  598. addServerMessageHandler = new GroupHandler<ServerMessage, string>(
  599. handleFunc: BundleAddServerMessage,
  600. logger: loggerFactory.CreateLogger("AddServerMessageHandler"));
  601. }
  602. private void InitUpdateMachineBasicInfoHandler()
  603. {
  604. if (updateMachineBasicInfoHandler is not null)
  605. {
  606. throw new Exception($"{nameof(InitUpdateMachineBasicInfoHandler)} should only called once");
  607. }
  608. updateMachineBasicInfoHandler = new GroupHandler<UpdateMachineBasicInfoParam>(
  609. handleFunc: BundelUpdateMachineBasicInfo,
  610. logger: loggerFactory.CreateLogger("UpdateMachineBasicInfoHandler"),
  611. workerCnt: 1);
  612. }
  613. private void InitUpdateServerMessageUpdateOnHandler()
  614. {
  615. if (updateServerMessageUpdateOnHandler is not null)
  616. {
  617. throw new Exception($"{nameof(InitUpdateMachineBasicInfoHandler)} should only called once");
  618. }
  619. updateServerMessageUpdateOnHandler = new GroupHandler<int>(
  620. handleFunc: BundelUpdateServerMessageUpdateOn,
  621. logger: loggerFactory.CreateLogger("UpdateServerMessageUpdateOnHandler"),
  622. workerCnt: 10);
  623. }
  624. private void InitGetMachineConfigurationHandler()
  625. {
  626. if (getMachineConfigurationHandler is not null)
  627. {
  628. throw new Exception($"{nameof(InitUpdateMachineBasicInfoHandler)} should only called once");
  629. }
  630. getMachineConfigurationHandler = new GroupHandler<string, List<MachineConfigurations>>(
  631. handleFunc: BundelGetMachineConfiguration,
  632. logger: loggerFactory.CreateLogger("GetMachineConfigurationHandler"),
  633. workerCnt: 10);
  634. }
  635. private void InitUpdateErrorFinishedOnHandler()
  636. {
  637. if (updateErrorFinishedOnHandler is not null)
  638. {
  639. throw new Exception($"{nameof(InitUpdateErrorFinishedOnHandler)} should only called once");
  640. }
  641. updateErrorFinishedOnHandler = new GroupHandler<UpdateErrofFinishedOnParam>(
  642. handleFunc: BundelUpdateErrorFinishedOn,
  643. logger: loggerFactory.CreateLogger("UpdateErrorFinishedOnHandler"),
  644. workerCnt: 1);
  645. }
  646. private async Task UpdateMachineBasicInfoEF(string chargeBoxId, Machine machine)
  647. {
  648. using var semaphoreWrapper = await startupSemaphore.GetToken();
  649. using var db = await contextFactory.CreateDbContextAsync();
  650. var _machine = await db.Machine.FirstOrDefaultAsync(x => x.ChargeBoxId == chargeBoxId);
  651. _machine.ChargeBoxSerialNumber = machine.ChargeBoxSerialNumber;
  652. _machine.ChargePointSerialNumber = machine.ChargePointSerialNumber;
  653. _machine.ChargePointModel = machine.ChargePointModel;
  654. _machine.ChargePointVendor = machine.ChargePointVendor;
  655. _machine.FwCurrentVersion = machine.FwCurrentVersion;
  656. _machine.Iccid = machine.Iccid;
  657. _machine.Imsi = machine.Imsi;
  658. _machine.MeterSerialNumber = machine.MeterSerialNumber;
  659. _machine.MeterType = machine.MeterType;
  660. await db.SaveChangesAsync();
  661. //using var semaphoreWrapper = await startupSemaphore.GetToken();
  662. }
  663. private async Task BundelUpdateMachineBasicInfo(BundleHandlerData<UpdateMachineBasicInfoParam> bundleHandlerData)
  664. {
  665. using var db = await contextFactory.CreateDbContextAsync();
  666. using var trans = await db.Database.BeginTransactionAsync();
  667. var pams = bundleHandlerData.Datas.DistinctBy(x => x.ChargeBoxId);
  668. foreach (var pam in pams)
  669. {
  670. var _machine = db.Machine.FirstOrDefault(x => x.ChargeBoxId == pam.ChargeBoxId);
  671. _machine.ChargeBoxSerialNumber = pam.machine.ChargeBoxSerialNumber;
  672. _machine.ChargePointSerialNumber = pam.machine.ChargePointSerialNumber;
  673. _machine.ChargePointModel = pam.machine.ChargePointModel;
  674. _machine.ChargePointVendor = pam.machine.ChargePointVendor;
  675. _machine.FwCurrentVersion = pam.machine.FwCurrentVersion;
  676. _machine.Iccid = pam.machine.Iccid;
  677. _machine.Imsi = pam.machine.Imsi;
  678. _machine.MeterSerialNumber = pam.machine.MeterSerialNumber;
  679. _machine.MeterType = pam.machine.MeterType;
  680. }
  681. await db.SaveChangesAsync();
  682. await trans.CommitAsync();
  683. bundleHandlerData.CompletedDatas.AddRange(bundleHandlerData.Datas);
  684. }
  685. private async Task BundelUpdateServerMessageUpdateOn(BundleHandlerData<int> bundleHandlerData)
  686. {
  687. var ids = bundleHandlerData.Datas;
  688. var sql = """
  689. UPDATE [dbo].[ServerMessage]
  690. SET UpdatedOn = @DateTimeNow
  691. WHERE Id in @Ids
  692. """;
  693. DynamicParameters parameters = new DynamicParameters();
  694. parameters.Add("DateTimeNow", DateTime.UtcNow, DbType.DateTime);
  695. parameters.Add("Ids", ids);
  696. using SqlConnection sqlConnection = await sqlConnectionFactory.CreateAsync();
  697. var cnt = await sqlConnection.ExecuteAsync(sql, parameters);
  698. if (cnt != 0 || ids.Count == 0)
  699. {
  700. bundleHandlerData.CompletedDatas.AddRange(ids);
  701. }
  702. }
  703. private async Task BundelGetMachineConfiguration(BundleHandlerData<string, List<MachineConfigurations>> bundleHandlerData)
  704. {
  705. var chargeboxIds = bundleHandlerData.Datas;
  706. var sql = """
  707. SELECT [ChargeBoxId], [ConfigureName], [ConfigureSetting], [ReadOnly], [Exists]
  708. FROM [dbo].[MachineConfigurations]
  709. WHERE ChargeBoxId IN @ChargeBoxIds
  710. """;
  711. DynamicParameters parameters = new DynamicParameters();
  712. parameters.Add("@ChargeBoxIds", chargeboxIds, direction: ParameterDirection.Input, size: 25);
  713. using SqlConnection sqlConnection = await sqlConnectionFactory.CreateAsync();
  714. var result = await sqlConnection.QueryAsync<MachineConfigurations>(sql, parameters);
  715. var gReult = result.GroupBy(x => x.ChargeBoxId);
  716. foreach (var g in gReult)
  717. {
  718. var originKey = chargeboxIds.FirstOrDefault(x => x.ToLower() == g.Key.ToLower());
  719. if (string.IsNullOrEmpty(originKey))
  720. {
  721. continue;
  722. }
  723. bundleHandlerData.AddCompletedData(originKey, g.ToList());
  724. }
  725. var getConfigChargeboxIds = gReult.Select(x => x.Key);
  726. var emptyConfigChargeboxIds = chargeboxIds.Except(getConfigChargeboxIds);
  727. foreach (var chargeboxId in emptyConfigChargeboxIds)
  728. {
  729. bundleHandlerData.AddCompletedData(chargeboxId, new List<MachineConfigurations>());
  730. }
  731. }
  732. private async Task UpdateConnectorStatusEF(string Id, ConnectorStatus Status)
  733. {
  734. using var db = await contextFactory.CreateDbContextAsync();
  735. ConnectorStatus status = new() { Id = Id };
  736. db.ChangeTracker.AutoDetectChangesEnabled = false;
  737. db.ConnectorStatus.Attach(status);
  738. status.CreatedOn = Status.CreatedOn;
  739. status.Status = Status.Status;
  740. status.ChargePointErrorCodeId = Status.ChargePointErrorCodeId;
  741. status.ErrorInfo = Status.ErrorInfo;
  742. status.VendorId = Status.VendorId;
  743. status.VendorErrorCode = Status.VendorErrorCode;
  744. db.Entry(status).Property(x => x.CreatedOn).IsModified = true;
  745. db.Entry(status).Property(x => x.Status).IsModified = true;
  746. db.Entry(status).Property(x => x.ChargePointErrorCodeId).IsModified = true;
  747. db.Entry(status).Property(x => x.ErrorInfo).IsModified = true;
  748. db.Entry(status).Property(x => x.VendorId).IsModified = true;
  749. db.Entry(status).Property(x => x.VendorErrorCode).IsModified = true;
  750. await db.SaveChangesAsync();
  751. }
  752. private async Task UpdateConnectorStatusDapper(string Id, ConnectorStatus Status)
  753. {
  754. var parameters = new DynamicParameters();
  755. parameters.Add("@Id", Id, DbType.String, ParameterDirection.Input, 36);
  756. parameters.Add("@CreatedOn", Status.CreatedOn, DbType.DateTime, ParameterDirection.Input);
  757. parameters.Add("@Status", Status.Status, DbType.Int32, ParameterDirection.Input);
  758. parameters.Add("@ChargePointErrorCodeId", Status.ChargePointErrorCodeId, DbType.Int32, ParameterDirection.Input);
  759. parameters.Add("@ErrorInfo", Status.ErrorInfo, DbType.String, ParameterDirection.Input, 50);
  760. parameters.Add("@VendorId", Status.VendorId, DbType.String, ParameterDirection.Input, 255);
  761. parameters.Add("@VendorErrorCode", Status.VendorErrorCode, DbType.String, ParameterDirection.Input, 100);
  762. using var conn = await sqlConnectionFactory.CreateAsync();
  763. await conn.ExecuteAsync("""
  764. update ConnectorStatus
  765. set
  766. CreatedOn = @CreatedOn,
  767. Status = @Status,
  768. ChargePointErrorCodeId = @ChargePointErrorCodeId,
  769. ErrorInfo = @ErrorInfo,
  770. VendorId = @VendorId,
  771. VendorErrorCode = @VendorErrorCode
  772. where Id = @Id
  773. """, parameters);
  774. }
  775. private async Task<Guid> GetCustomerIdByChargeBoxIdEF(string chargeboxId)
  776. {
  777. using var db = await contextFactory.CreateDbContextAsync();
  778. var _CustomerId = await db.Machine.Where(x => x.ChargeBoxId == chargeboxId).Select(x => x.CustomerId).FirstOrDefaultAsync();
  779. return _CustomerId;
  780. }
  781. private async Task<Guid> GetCustomerIdByChargeBoxIdDapper(string chargeboxId)
  782. {
  783. var parameters = new DynamicParameters();
  784. parameters.Add("@ChargeBoxId", chargeboxId, DbType.String, ParameterDirection.Input, 50);
  785. using var conn = await sqlConnectionFactory.CreateAsync();
  786. var _existedTx = await conn.QueryFirstOrDefaultAsync<Guid>("""
  787. select CustomerId
  788. from dbo.Machine
  789. where
  790. ChargeBoxId = @ChargeBoxId
  791. """, parameters);
  792. return _existedTx;
  793. }
  794. private async Task<int?> TryGetDuplicatedTransactionIdEF(string chargeBoxId, Guid customerId, int connectorId, DateTime timestamp)
  795. {
  796. using var db = await contextFactory.CreateDbContextAsync();
  797. var _existedTx = await db.TransactionRecord.Where(x => x.CustomerId == customerId && x.ChargeBoxId == chargeBoxId
  798. && x.ConnectorId == connectorId && x.StartTime == timestamp).Select(x => x.Id).FirstOrDefaultAsync();
  799. return _existedTx;
  800. }
  801. private async Task<int?> TryGetDuplicatedTransactionIdDapper(string chargeBoxId, Guid customerId, int connectorId, DateTime timestamp)
  802. {
  803. var parameters = new DynamicParameters();
  804. parameters.Add("@ChargeBoxId", chargeBoxId, DbType.String, ParameterDirection.Input, 50);
  805. parameters.Add("@CustomerId", customerId, DbType.Guid, ParameterDirection.Input);
  806. parameters.Add("@ConnectorId", connectorId, DbType.Int16, ParameterDirection.Input);
  807. parameters.Add("@TimeStamp", timestamp, DbType.DateTime, ParameterDirection.Input);
  808. using var conn = await sqlConnectionFactory.CreateAsync();
  809. var _existedTx = await conn.QueryFirstOrDefaultAsync<int?>("""
  810. SELECT Id
  811. FROM dbo.TransactionRecord
  812. WHERE
  813. ChargeBoxId = @ChargeBoxId and
  814. CustomerId = @CustomerId and
  815. ConnectorId = @ConnectorId and
  816. StartTime = @TimeStamp
  817. """, parameters);
  818. return _existedTx;
  819. }
  820. private async ValueTask AddMachineErrorEF(byte connectorId, DateTime createdOn, int status, string chargeBoxId, int errorCodeId, string errorInfo, int preStatus, string vendorErrorCode, string vendorId)
  821. {
  822. using var db = await contextFactory.CreateDbContextAsync();
  823. await db.MachineError.AddAsync(new MachineError()
  824. {
  825. ConnectorId = connectorId,
  826. CreatedOn = createdOn,
  827. Status = status,
  828. ChargeBoxId = chargeBoxId,
  829. ErrorCodeId = errorCodeId,
  830. ErrorInfo = errorInfo,
  831. PreStatus = preStatus,
  832. VendorErrorCode = vendorErrorCode,
  833. VendorId = vendorId
  834. });
  835. await db.SaveChangesAsync();
  836. }
  837. private async ValueTask AddMachineErrorDapper(byte connectorId, DateTime createdOn, int status, string chargeBoxId, int errorCodeId, string errorInfo, int preStatus, string vendorErrorCode, string vendorId)
  838. {
  839. var parameters = new DynamicParameters();
  840. parameters.Add("@ConnectorId", connectorId, DbType.Int16, ParameterDirection.Input);
  841. parameters.Add("@PreStatus", preStatus, DbType.Int32, ParameterDirection.Input);
  842. parameters.Add("@Status", status, DbType.Int32, ParameterDirection.Input);
  843. parameters.Add("@ErrorInfo", errorInfo, DbType.String, ParameterDirection.Input, 50);
  844. parameters.Add("@VendorId", vendorId, DbType.String, ParameterDirection.Input, 255);
  845. parameters.Add("@CreatedOn", createdOn, DbType.DateTime, ParameterDirection.Input);
  846. parameters.Add("@ErrorCodeId", errorCodeId, DbType.Int32, ParameterDirection.Input);
  847. parameters.Add("@VendorErrorCode", vendorErrorCode, DbType.String, ParameterDirection.Input, 100);
  848. parameters.Add("@ChargeBoxId", chargeBoxId, DbType.String, ParameterDirection.Input, 50);
  849. using var conn = await sqlConnectionFactory.CreateAsync();
  850. await conn.ExecuteAsync("""
  851. INSERT INTO MachineError
  852. (ConnectorId, PreStatus, Status, ErrorInfo, VendorId, CreatedOn, ErrorCodeId, VendorErrorCode, ChargeBoxId)
  853. VALUES (@ConnectorId, @PreStatus, @Status, @ErrorInfo, @VendorId, @CreatedOn, @ErrorCodeId, @VendorErrorCode, @ChargeBoxId)
  854. """, parameters);
  855. }
  856. private async ValueTask AddFinishedTimetoMachineErrorDapper(string chargeBoxId, byte connectorId, DateTime finishedTime)
  857. {
  858. var getCommand = """
  859. SELECT TOP(1) Id
  860. FROM [dbo].[MachineError]
  861. where ChargeBoxId=@ChargeBoxId and ConnectorId=@ConnectorId
  862. Order by Id desc
  863. """;
  864. var parameters = new DynamicParameters();
  865. parameters.Add("@ConnectorId", connectorId, DbType.Int16, ParameterDirection.Input);
  866. parameters.Add("@ChargeBoxId", chargeBoxId, DbType.String, ParameterDirection.Input, 50);
  867. //parameters.Add("@CreatedOn", previousErrorOn, DbType.DateTime, ParameterDirection.Input, 50);
  868. int? recordId = null;
  869. using (var conn = await sqlConnectionFactory.CreateAsync())
  870. {
  871. recordId = await conn.QueryFirstOrDefaultAsync<int?>(getCommand, parameters);
  872. if (recordId is null)
  873. {
  874. return;
  875. }
  876. }
  877. await updateErrorFinishedOnHandler.HandleAsync(new UpdateErrofFinishedOnParam(recordId.Value, finishedTime));
  878. }
  879. private async Task BundelUpdateErrorFinishedOn(BundleHandlerData<UpdateErrofFinishedOnParam> bundleHandlerData)
  880. {
  881. var updateCommand = """
  882. Update MachineError
  883. set FinishedOn=@FinishedOn
  884. where Id=@Id
  885. """;
  886. var pams = bundleHandlerData.Datas;
  887. using var conn = await sqlConnectionFactory.CreateAsync();
  888. using var trans = await conn.BeginTransactionAsync();
  889. DynamicParameters parameters = null;
  890. foreach (var pam in pams)
  891. {
  892. parameters = new DynamicParameters();
  893. parameters.Add("@Id", pam.Id, DbType.Int32, ParameterDirection.Input);
  894. parameters.Add("@FinishedOn", pam.finishedOn, DbType.DateTime, ParameterDirection.Input);
  895. await conn.ExecuteAsync(new CommandDefinition(
  896. updateCommand,
  897. parameters: parameters,
  898. transaction: trans
  899. ));
  900. }
  901. await trans.CommitAsync();
  902. bundleHandlerData.CompletedDatas.AddRange(bundleHandlerData.Datas);
  903. }
  904. private async Task BundleUpdateConnectorStatus(IEnumerable<StatusNotificationParam> statusNotifications)
  905. {
  906. using var db = await contextFactory.CreateDbContextAsync();
  907. using var trans = await db.Database.BeginTransactionAsync();
  908. statusNotifications = statusNotifications.OrderBy(x => x.Status.CreatedOn).DistinctBy(x => x.Id);
  909. foreach (var param in statusNotifications)
  910. {
  911. ConnectorStatus status = new() { Id = param.Id };
  912. //db.ChangeTracker.AutoDetectChangesEnabled = false;
  913. db.ConnectorStatus.Attach(status);
  914. status.CreatedOn = param.Status.CreatedOn;
  915. status.Status = param.Status.Status;
  916. status.ChargePointErrorCodeId = param.Status.ChargePointErrorCodeId;
  917. status.ErrorInfo = param.Status.ErrorInfo;
  918. status.VendorId = param.Status.VendorId;
  919. status.VendorErrorCode = param.Status.VendorErrorCode;
  920. db.Entry(status).Property(x => x.CreatedOn).IsModified = true;
  921. db.Entry(status).Property(x => x.Status).IsModified = true;
  922. db.Entry(status).Property(x => x.ChargePointErrorCodeId).IsModified = true;
  923. db.Entry(status).Property(x => x.ErrorInfo).IsModified = true;
  924. db.Entry(status).Property(x => x.VendorId).IsModified = true;
  925. db.Entry(status).Property(x => x.VendorErrorCode).IsModified = true;
  926. //await db.SaveChangesAsync();
  927. }
  928. await db.SaveChangesAsync();
  929. await trans.CommitAsync();
  930. //db.ChangeTracker.Clear();
  931. }
  932. private async Task BundleUpdateConnectorStatusDapper(BundleHandlerData<StatusNotificationParam> bundleHandlerData)
  933. {
  934. using var conn = await sqlConnectionFactory.CreateAsync();
  935. foreach (var status in bundleHandlerData.Datas)
  936. {
  937. var parameters = new DynamicParameters();
  938. parameters.Add("@Id", status.Id, DbType.String, ParameterDirection.Input, 36);
  939. parameters.Add("@CreatedOn", status.Status.CreatedOn, DbType.DateTime, ParameterDirection.Input);
  940. parameters.Add("@Status", status.Status.Status, DbType.Int32, ParameterDirection.Input);
  941. parameters.Add("@ChargePointErrorCodeId", status.Status.ChargePointErrorCodeId, DbType.Int32, ParameterDirection.Input);
  942. parameters.Add("@ErrorInfo", status.Status.ErrorInfo, DbType.String, ParameterDirection.Input, 50);
  943. parameters.Add("@VendorId", status.Status.VendorId, DbType.String, ParameterDirection.Input, 255);
  944. parameters.Add("@VendorErrorCode", status.Status.VendorErrorCode, DbType.String, ParameterDirection.Input, 100);
  945. await conn.ExecuteAsync("""
  946. update ConnectorStatus
  947. set
  948. CreatedOn = @CreatedOn,
  949. Status = @Status,
  950. ChargePointErrorCodeId = @ChargePointErrorCodeId,
  951. ErrorInfo = @ErrorInfo,
  952. VendorId = @VendorId,
  953. VendorErrorCode = @VendorErrorCode
  954. where Id = @Id
  955. """, parameters);
  956. bundleHandlerData.AddCompletedData(status);
  957. }
  958. }
  959. private async Task BundleAddServerMessage(BundleHandlerData<ServerMessage, string> bundleHandlerData)
  960. {
  961. //var sql = """
  962. // INSERT INTO [ServerMessage] ([ChargeBoxId], [CreatedBy], [CreatedOn], [InMessage], [OutAction], [OutRequest], [ReceivedOn], [SerialNo], [UpdatedOn])
  963. // OUTPUT INSERTED.Id
  964. // VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8)
  965. // """;
  966. //using var conn = await sqlConnectionFactory.CreateAsync();
  967. //foreach(var data in bundleHandlerData.Datas)
  968. //{
  969. // var dymparam = new DynamicParameters();
  970. // dymparam.Add("@p0", data.ChargeBoxId);
  971. // dymparam.Add("@p1", data.CreatedBy);
  972. // dymparam.Add("@p2", data.CreatedOn);
  973. // dymparam.Add("@p3", data.InMessage);
  974. // dymparam.Add("@p4", data.OutAction);
  975. // dymparam.Add("@p5", data.OutRequest);
  976. // dymparam.Add("@p6", data.ReceivedOn);
  977. // dymparam.Add("@p7", data.SerialNo);
  978. // dymparam.Add("@p8", data.UpdatedOn);
  979. //}
  980. using var db = await contextFactory.CreateDbContextAsync();
  981. using var trans = await db.Database.BeginTransactionAsync();
  982. foreach (var message in bundleHandlerData.Datas)
  983. {
  984. await db.ServerMessage.AddAsync(message);
  985. }
  986. await db.SaveChangesAsync();
  987. await trans.CommitAsync();
  988. bundleHandlerData.CompletedDatas.AddRange(bundleHandlerData.Datas.Select(x => new KeyValuePair<ServerMessage, string>(x, x.SerialNo)));
  989. }
  990. private async Task AddServerMessageEF(ServerMessage message)
  991. {
  992. using var db = await contextFactory.CreateDbContextAsync();
  993. using var trans = await db.Database.BeginTransactionAsync();
  994. await db.ServerMessage.AddAsync(message);
  995. await db.SaveChangesAsync();
  996. await trans.CommitAsync();
  997. //db.ChangeTracker.Clear();
  998. }
  999. private async Task AddServerMessageDapper(ServerMessage message)
  1000. {
  1001. var parameters = new DynamicParameters();
  1002. parameters.Add("@SerialNo", message.SerialNo, DbType.String, ParameterDirection.Input, 36);
  1003. parameters.Add("@OutAction", message.OutAction, DbType.String, ParameterDirection.Input, 30);
  1004. parameters.Add("@OutRequest", message.OutRequest, DbType.String, ParameterDirection.Input);
  1005. parameters.Add("@InMessage", message.InMessage, DbType.String, ParameterDirection.Input);
  1006. parameters.Add("@CreatedOn", message.CreatedOn, DbType.DateTime, ParameterDirection.Input);
  1007. parameters.Add("@CreatedBy", message.CreatedBy, DbType.String, ParameterDirection.Input, 36);
  1008. parameters.Add("@ReceivedOn", message.ReceivedOn, DbType.DateTime, ParameterDirection.Input);
  1009. parameters.Add("@ChargeBoxId", message.ChargeBoxId, DbType.String, ParameterDirection.Input, 30);
  1010. parameters.Add("@UpdatedOn", message.UpdatedOn, DbType.DateTime, ParameterDirection.Input);
  1011. using var conn = await sqlConnectionFactory.CreateAsync();
  1012. var resultCnt = await conn.ExecuteAsync("""
  1013. INSERT INTO ServerMessage
  1014. (SerialNo, OutAction, OutRequest, InMessage, CreatedOn, CreatedBy, ReceivedOn, ChargeBoxId, UpdatedOn)
  1015. VALUES (@SerialNo, @OutAction, @OutRequest, @InMessage, @CreatedOn, @CreatedBy, @ReceivedOn, @ChargeBoxId, @UpdatedOn)
  1016. """, parameters);
  1017. if (resultCnt != 1)
  1018. {
  1019. throw new Exception("Insert failed");
  1020. }
  1021. return;
  1022. }
  1023. private async Task<int> AddNewTransactionRecordEF(TransactionRecord newTransaction)
  1024. {
  1025. using var db = await contextFactory.CreateDbContextAsync();
  1026. await db.TransactionRecord.AddAsync(newTransaction);
  1027. await db.SaveChangesAsync();
  1028. return newTransaction.Id;
  1029. }
  1030. private async Task<int> AddNewTransactionRecordDapper(TransactionRecord newTransaction)
  1031. {
  1032. var parameters = new DynamicParameters();
  1033. parameters.Add("@ChargeBoxId", newTransaction.ChargeBoxId, DbType.String, ParameterDirection.Input, 50);
  1034. parameters.Add("@ConnectorId", newTransaction.ConnectorId, DbType.Int16, ParameterDirection.Input);
  1035. parameters.Add("@CreatedOn", newTransaction.CreatedOn, DbType.DateTime, ParameterDirection.Input);
  1036. parameters.Add("@UpdatedOn", newTransaction.UpdatedOn, DbType.DateTime, ParameterDirection.Input);
  1037. parameters.Add("@StartTransactionReportedOn", newTransaction.StartTransactionReportedOn, DbType.DateTime, ParameterDirection.Input);
  1038. parameters.Add("@StopTransactionReportedOn", newTransaction.StopTransactionReportedOn, DbType.DateTime, ParameterDirection.Input);
  1039. parameters.Add("@StartIdTag", newTransaction.StartIdTag, DbType.String, ParameterDirection.Input, 20);
  1040. parameters.Add("@MeterStart", newTransaction.MeterStart, DbType.Decimal, ParameterDirection.Input, precision: 18, scale: 2);
  1041. parameters.Add("@MeterStop", newTransaction.MeterStop, DbType.Decimal, ParameterDirection.Input, precision: 18, scale: 2);
  1042. parameters.Add("@CustomerId", newTransaction.CustomerId, DbType.Guid, ParameterDirection.Input);
  1043. parameters.Add("@StartTime", newTransaction.StartTime, DbType.DateTime, ParameterDirection.Input);
  1044. parameters.Add("@StopTime", newTransaction.StopTime, DbType.DateTime, ParameterDirection.Input);
  1045. parameters.Add("@ReservationId", newTransaction.ReservationId, DbType.Int32, ParameterDirection.Input);
  1046. parameters.Add("@RetryStartTransactionTimes", newTransaction.RetryStartTransactionTimes, DbType.Int32, ParameterDirection.Input);
  1047. parameters.Add("@RetryStopTransactionTimes", newTransaction.RetryStopTransactionTimes, DbType.Int32, ParameterDirection.Input);
  1048. parameters.Add("@Fee", newTransaction.Fee, DbType.String, ParameterDirection.Input, 1500);
  1049. using var conn = await sqlConnectionFactory.CreateAsync();
  1050. var id = await conn.QuerySingleAsync<int>("""
  1051. INSERT INTO TransactionRecord
  1052. (ChargeBoxId, ConnectorId, CreatedOn, UpdatedOn, StartTransactionReportedOn, StopTransactionReportedOn,
  1053. StartIdTag, MeterStart, MeterStop, CustomerId, StartTime, StopTime, ReservationId, RetryStartTransactionTimes, RetryStopTransactionTimes, Fee)
  1054. OUTPUT INSERTED.Id
  1055. VALUES (@ChargeBoxId, @ConnectorId, @CreatedOn, @UpdatedOn, @StartTransactionReportedOn, @StopTransactionReportedOn,
  1056. @StartIdTag, @MeterStart, @MeterStop, @CustomerId, @StartTime, @StopTime, @ReservationId, @RetryStartTransactionTimes, @RetryStopTransactionTimes, @Fee)
  1057. """, parameters);
  1058. return id;
  1059. }
  1060. private async Task<TransactionRecord> GetTransactionForStopTransactionEF(int transactionId, string chargeBoxId)
  1061. {
  1062. using var db = await contextFactory.CreateDbContextAsync();
  1063. return await db.TransactionRecord.Where(x => x.Id == transactionId
  1064. && x.ChargeBoxId == chargeBoxId).FirstOrDefaultAsync();
  1065. }
  1066. private async Task<TransactionRecord> GetTransactionForStopTransactionDapper(int transactionId, string chargeBoxId)
  1067. {
  1068. var parameters = new DynamicParameters();
  1069. parameters.Add("@TransactionId", transactionId, DbType.Int32, ParameterDirection.Input);
  1070. parameters.Add("@ChargeBoxId", chargeBoxId, DbType.String, ParameterDirection.Input, 50);
  1071. using var conn = await sqlConnectionFactory.CreateAsync();
  1072. var record = await conn.QuerySingleAsync<TransactionRecord>("""
  1073. SELECT Id, ConnectorId, MeterStop, MeterStart, StartTime, StopTime FROM TransactionRecord
  1074. WHERE Id = @TransactionId and ChargeBoxId = @ChargeBoxId
  1075. """, parameters);
  1076. return record;
  1077. }
  1078. private Task BulkInsertServerMessage(IEnumerable<ServerMessage> messages)
  1079. {
  1080. var table = new DataTable();
  1081. table.Columns.Add("ChargeBoxId");
  1082. table.Columns.Add("SerialNo");
  1083. table.Columns.Add("OutAction");
  1084. table.Columns.Add("OutRequest");
  1085. table.Columns.Add("InMessage");
  1086. table.Columns.Add("CreatedOn");
  1087. table.Columns.Add("CreatedBy");
  1088. table.Columns.Add("UpdatedOn");
  1089. table.Columns.Add("ReceivedOn");
  1090. foreach (var param in messages)
  1091. {
  1092. var row = table.NewRow();
  1093. row["ChargeBoxId"] = param.ChargeBoxId;
  1094. row["SerialNo"] = param.SerialNo;
  1095. row["OutAction"] = param.OutAction;
  1096. row["OutRequest"] = param.OutRequest;
  1097. row["InMessage"] = param.InMessage;
  1098. row["CreatedOn"] = param.CreatedOn;
  1099. row["CreatedBy"] = param.CreatedBy;
  1100. row["UpdatedOn"] = param.UpdatedOn;
  1101. row["ReceivedOn"] = param.ReceivedOn;
  1102. table.Rows.Add(row);
  1103. }
  1104. using SqlConnection sqlConnection = sqlConnectionFactory.Create();
  1105. using SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(sqlConnection);
  1106. sqlBulkCopy.BatchSize = messages.Count();
  1107. sqlBulkCopy.DestinationTableName = "ServerMessage";
  1108. sqlBulkCopy.ColumnMappings.Add("ChargeBoxId", "ChargeBoxId");
  1109. sqlBulkCopy.ColumnMappings.Add("SerialNo", "SerialNo");
  1110. sqlBulkCopy.ColumnMappings.Add("OutAction", "OutAction");
  1111. sqlBulkCopy.ColumnMappings.Add("OutRequest", "OutRequest");
  1112. sqlBulkCopy.ColumnMappings.Add("InMessage", "InMessage");
  1113. sqlBulkCopy.ColumnMappings.Add("CreatedOn", "CreatedOn");
  1114. sqlBulkCopy.ColumnMappings.Add("CreatedBy", "CreatedBy");
  1115. sqlBulkCopy.ColumnMappings.Add("UpdatedOn", "UpdatedOn");
  1116. sqlBulkCopy.ColumnMappings.Add("ReceivedOn", "ReceivedOn");
  1117. return sqlBulkCopy.WriteToServerAsync(table);
  1118. }
  1119. private int GetStartupLimit(IConfiguration configuration)
  1120. {
  1121. var limitConfig = configuration["MainDbStartupLimit"];
  1122. int limit = 5;
  1123. if (limitConfig != default)
  1124. {
  1125. int.TryParse(limitConfig, out limit);
  1126. }
  1127. return limit;
  1128. }
  1129. private int GetOpLimit(IConfiguration configuration)
  1130. {
  1131. var limitConfig = configuration["MainDbOpLimit"];
  1132. int limit = 500;
  1133. if (limitConfig != default)
  1134. {
  1135. int.TryParse(limitConfig, out limit);
  1136. }
  1137. return limit;
  1138. }
  1139. private async Task<bool> UpdateHeartBeatsDapper(IEnumerable<Machine> heartBeatsData)
  1140. {
  1141. using var conn = await sqlConnectionFactory.CreateAsync();
  1142. using var trans = await conn.BeginTransactionAsync();
  1143. try
  1144. {
  1145. foreach (var data in heartBeatsData)
  1146. {
  1147. var parameters = new DynamicParameters();
  1148. parameters.Add("@Id", data.Id, DbType.String, ParameterDirection.Input, 36);
  1149. parameters.Add("@HeartbeatUpdatedOn", data.HeartbeatUpdatedOn, DbType.DateTime, ParameterDirection.Input);
  1150. parameters.Add("@ConnectionType", data.ConnectionType, DbType.Int32, ParameterDirection.Input);
  1151. var resultCnt = await conn.ExecuteAsync("""
  1152. UPDATE Machine
  1153. SET HeartbeatUpdatedOn = @HeartbeatUpdatedOn, ConnectionType = @ConnectionType
  1154. WHERE Id = @Id
  1155. """, parameters, trans);
  1156. if (resultCnt != 1)
  1157. {
  1158. throw new Exception("Update over one columes");
  1159. }
  1160. }
  1161. await trans.CommitAsync();
  1162. }
  1163. catch
  1164. {
  1165. logger.LogCritical("HeartBeatCheckTrigger update fail, roll back");
  1166. await trans.RollbackAsync();
  1167. return false;
  1168. }
  1169. return true;
  1170. }
  1171. private async Task<bool> UpdateHeartBeatsDapper(List<string> machineIds)
  1172. {
  1173. using var conn = await sqlConnectionFactory.CreateAsync();
  1174. try
  1175. {
  1176. var parameters = new DynamicParameters();
  1177. parameters.Add("@Ids", machineIds, size: 36);
  1178. parameters.Add("@HeartbeatUpdatedOn", DateTime.UtcNow, DbType.DateTime, ParameterDirection.Input);
  1179. var resultCnt = await conn.ExecuteAsync("""
  1180. UPDATE Machine
  1181. SET HeartbeatUpdatedOn = @HeartbeatUpdatedOn
  1182. WHERE Id in @Ids
  1183. """, parameters);
  1184. }
  1185. catch (Exception e)
  1186. {
  1187. logger.LogError(e.Message);
  1188. logger.LogCritical("HeartBeatCheckTrigger update fail");
  1189. return false;
  1190. }
  1191. return true;
  1192. }
  1193. private async Task<bool> UpdateHeartBeatsEF(IEnumerable<Machine> heartBeatsData)
  1194. {
  1195. using var db = await contextFactory.CreateDbContextAsync();
  1196. using var transaction = await db.Database.BeginTransactionAsync();
  1197. try
  1198. {
  1199. foreach (var data in heartBeatsData)
  1200. {
  1201. var machine = new Machine() { Id = data.Id };
  1202. if (machine != null)
  1203. {
  1204. db.Machine.Attach(machine);
  1205. machine.HeartbeatUpdatedOn = DateTime.UtcNow;
  1206. machine.ConnectionType = data.ConnectionType;
  1207. db.Entry(machine).Property(x => x.HeartbeatUpdatedOn).IsModified = true;
  1208. db.Entry(machine).Property(x => x.ConnectionType).IsModified = true;
  1209. }
  1210. }
  1211. await db.SaveChangesAsync();
  1212. await transaction.CommitAsync();
  1213. db.ChangeTracker.Clear();
  1214. }
  1215. catch (Exception ex)
  1216. {
  1217. logger.LogCritical(ex, "HeartBeatCheckTrigger update fail, roll back");
  1218. transaction.Rollback();
  1219. return false;
  1220. }
  1221. return true;
  1222. }
  1223. public async Task<string> GetMachineConnectorType(string chargeBoxId, CancellationToken token = default)
  1224. {
  1225. using var db = await contextFactory.CreateDbContextAsync(token);
  1226. var machine = await db.Machine.Where(x => x.ChargeBoxId == chargeBoxId).FirstOrDefaultAsync(token);
  1227. if (machine == null)
  1228. {
  1229. return null;
  1230. }
  1231. return machine.ConnectorType;
  1232. }
  1233. public async Task SetMachineConnectionType(string chargeBoxId, int v, CancellationToken token = default)
  1234. {
  1235. using var db = await contextFactory.CreateDbContextAsync(token);
  1236. var machine = await db.Machine.Where(x => x.ChargeBoxId == chargeBoxId).FirstOrDefaultAsync(token);
  1237. if (machine == null)
  1238. {
  1239. return;
  1240. }
  1241. machine.ConnectionType = v;
  1242. return;
  1243. }
  1244. public async Task<Dictionary<string, decimal>> GetTransactionPeriodEnergy(int transactionId)
  1245. {
  1246. var parms = new DynamicParameters();
  1247. parms.Add("@TransactionId", transactionId);
  1248. var cmd = """
  1249. SELECT TOP(1)
  1250. [H00],[H01],[H02],[H03],[H04],[H05],[H06],[H07],[H08],[H09],[H10]
  1251. ,[H11],[H12],[H13],[H14],[H15],[H16],[H17],[H18],[H19],[H20]
  1252. ,[H21],[H22],[H23]
  1253. FROM [dbo].[TransactionPeriodEnergy]
  1254. WHERE TransactionId = @TransactionId
  1255. """;
  1256. using var dbConn = await sqlConnectionFactory.CreateAsync();
  1257. dynamic queryResult = await dbConn.QueryFirstOrDefaultAsync(cmd, parms);
  1258. if (queryResult is not IDictionary<string, object> queryResultPairs)
  1259. {
  1260. return null;
  1261. }
  1262. var toReturn = new Dictionary<string, decimal>();
  1263. for (int hour = 0; hour < 24; hour++)
  1264. {
  1265. var key = GetColName(hour);
  1266. if (queryResultPairs[key] is decimal value)
  1267. {
  1268. toReturn.Add(hour.ToString(), value);
  1269. }
  1270. }
  1271. return toReturn;
  1272. }
  1273. public async Task InsertOrUpdateTransactionPeriodEnergy(int txId, Dictionary<string, decimal> periodEnergy)
  1274. {
  1275. try
  1276. {
  1277. var isExists = await GetTransactionPeriodEnergyExists(txId);
  1278. var param = CreateParameters(txId, periodEnergy);
  1279. if (isExists)
  1280. {
  1281. await UpdateTransactionPeriodEnergy(param);
  1282. return;
  1283. }
  1284. await InsertTransactionPeriodEnergy(param);
  1285. }
  1286. catch (Exception e)
  1287. {
  1288. logger.LogError(e.Message);
  1289. }
  1290. return;
  1291. async Task<bool> GetTransactionPeriodEnergyExists(int txId)
  1292. {
  1293. var param = new DynamicParameters();
  1294. param.Add("@TransactionId", txId, DbType.Int32, ParameterDirection.Input);
  1295. var cmd = """
  1296. SELECT TransactionId
  1297. FROM TransactionPeriodEnergy
  1298. WHERE TransactionId = @TransactionId
  1299. """;
  1300. using var conn = await sqlConnectionFactory.CreateAsync();
  1301. return await conn.QueryFirstOrDefaultAsync<int?>(cmd, param) != null;
  1302. }
  1303. async Task<int> UpdateTransactionPeriodEnergy(DynamicParameters param)
  1304. {
  1305. var cmd = """
  1306. UPDATE TransactionPeriodEnergy
  1307. SET H00 = @H00, H01 = @H01, H02 = @H02, H03 = @H03, H04 = @H04, H05 = @H05, H06 = @H06, H07 = @H07, H08 = @H08,
  1308. H09 = @H09, H10 = @H10, H11 = @H11, H12 = @H12, H13 = @H13, H14 = @H14, H15 = @H15, H16 = @H16, H17 = @H17,
  1309. H18 = @H18, H19 = @H19, H20 = @H20, H21 = @H21, H22 = @H22, H23 = @H23
  1310. WHERE TransactionId = @TransactionId
  1311. """;
  1312. using var conn = await sqlConnectionFactory.CreateAsync();
  1313. return await conn.ExecuteAsync(cmd, param);
  1314. }
  1315. async Task InsertTransactionPeriodEnergy(DynamicParameters param)
  1316. {
  1317. var cmd = """
  1318. INSERT INTO TransactionPeriodEnergy
  1319. (TransactionId, H00, H01, H02, H03, H04, H05, H06, H07, H08, H09, H10, H11, H12, H13, H14, H15, H16, H17, H18, H19, H20, H21, H22, H23)
  1320. VALUES (@TransactionId, @H00, @H01, @H02, @H03, @H04, @H05, @H06, @H07, @H08, @H09, @H10, @H11, @H12, @H13, @H14, @H15, @H16, @H17, @H18, @H19, @H20, @H21, @H22, @H23)
  1321. """;
  1322. using var conn = await sqlConnectionFactory.CreateAsync();
  1323. await conn.ExecuteAsync(cmd, param);
  1324. }
  1325. DynamicParameters CreateParameters(int txId, Dictionary<string, decimal> periodEnergy)
  1326. {
  1327. var parameters = new DynamicParameters();
  1328. parameters.Add("@TransactionId", txId, DbType.Int32, ParameterDirection.Input);
  1329. for (int hour = 0; hour < 24; hour++)
  1330. {
  1331. var key = hour.ToString();
  1332. if (!periodEnergy.ContainsKey(key))
  1333. {
  1334. parameters.Add(GetColName(hour), 0, DbType.Decimal, ParameterDirection.Input, precision: 18, scale: 4);
  1335. continue;
  1336. }
  1337. parameters.Add(GetColName(hour), periodEnergy[key], DbType.Decimal, ParameterDirection.Input, precision: 18, scale: 4);
  1338. }
  1339. return parameters;
  1340. }
  1341. string GetColName(int hour)
  1342. {
  1343. return $"@H{hour.ToString("00")}";
  1344. }
  1345. }
  1346. string GetColName(int hour)
  1347. {
  1348. return $"H{hour.ToString("00")}";
  1349. }
  1350. }
  1351. public record MachineAndCustomerInfo(string MachineId, Guid CustomerId, string CustomerName);
  1352. public record StatusNotificationParam(string Id, ConnectorStatus Status);
  1353. public record UpdateMachineBasicInfoParam(string ChargeBoxId, Machine machine);
  1354. public record UpdateErrofFinishedOnParam(int Id, DateTime finishedOn);