MainDbService.cs 73 KB

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