ConnectorStatusDbService.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. using Dapper;
  2. using EVCB_OCPP.Domain;
  3. using EVCB_OCPP.Domain.ConnectionFactory;
  4. using EVCB_OCPP.WSServer.Dto;
  5. using EVCB_OCPP.WSServer.Helper;
  6. using Microsoft.Data.SqlClient;
  7. using Microsoft.EntityFrameworkCore;
  8. using Microsoft.EntityFrameworkCore.Metadata.Internal;
  9. using Microsoft.Extensions.Configuration;
  10. using Microsoft.Extensions.Logging;
  11. using System.Data;
  12. using System.Data.Common;
  13. using System.Diagnostics;
  14. namespace EVCB_OCPP.WSServer.Service.DbService;
  15. public class ConnectorStatusDbService
  16. {
  17. private readonly IDbContextFactory<OnlineRecordDBContext> onlineRecordDbContextFactory;
  18. private readonly ISqlConnectionFactory<OnlineRecordDBContext> sqlConnectionFactory;
  19. private readonly ILoggerFactory loggerFactory;
  20. private readonly ILogger logger;
  21. private readonly Queue<string> _existTables = new();
  22. public ConnectorStatusDbService(
  23. IDbContextFactory<OnlineRecordDBContext> onlineRecordDbContextFactory,
  24. ISqlConnectionFactory<OnlineRecordDBContext> sqlConnectionFactory,
  25. ILogger<ConnectorStatusDbService> logger,
  26. ILoggerFactory loggerFactory,
  27. IConfiguration configuration
  28. )
  29. {
  30. this.onlineRecordDbContextFactory = onlineRecordDbContextFactory;
  31. this.sqlConnectionFactory = sqlConnectionFactory;
  32. this.loggerFactory = loggerFactory;
  33. this.logger = logger;
  34. }
  35. public Task InsertAsync(string chargeBoxId, byte connectorId, int status, DateTime createdOn
  36. , string errorInfo, string vendorId, string vendorErrorCode, int chargePointErrorCodeId)
  37. {
  38. var param = new InsertConnectorStatusParam(chargeBoxId, connectorId, status, errorInfo
  39. , vendorId, createdOn, vendorErrorCode, chargePointErrorCodeId);
  40. return InsertAsync(param);
  41. }
  42. public Task InsertAsync(InsertConnectorStatusParam param)
  43. {
  44. return InsertWithDapper(param);
  45. }
  46. private async Task InsertWithDapper(InsertConnectorStatusParam param)
  47. {
  48. var watch = Stopwatch.StartNew();
  49. long t0, t1;
  50. if (!await GetTableExist(param.createdOn))
  51. {
  52. t0 = watch.ElapsedMilliseconds;
  53. await InsertWithStoredProcedure(param);
  54. watch.Stop();
  55. t1 = watch.ElapsedMilliseconds;
  56. if (t1 > 500)
  57. {
  58. logger.LogWarning("ConnectorStatusRecord InsertWithStoredProcedure {0}/{1}", t0, t1);
  59. }
  60. return;
  61. }
  62. t0 = watch.ElapsedMilliseconds;
  63. var tableName = GetTableName(param.createdOn);
  64. await InsertWithNoCheckDapper(tableName, param);
  65. watch.Stop();
  66. t1 = watch.ElapsedMilliseconds;
  67. if (t1 > 700)
  68. {
  69. logger.LogWarning("ConnectorStatusRecord Dapper {0}/{1}", t0, t1);
  70. }
  71. }
  72. private async Task InsertWithNoCheckDapper(string tableName, InsertConnectorStatusParam data, SqlConnection conn = null, DbTransaction trans = null)
  73. {
  74. string command = $"""
  75. INSERT INTO {tableName} ([ChargeBoxId],[ConnectorId]
  76. ,[Status],[CreatedOn],[ChargePointErrorCodeId],[ErrorInfo]
  77. ,[VendorId],[VendorErrorCode])
  78. VALUES (@ChargeBoxId,@ConnectorId, @Status, @CreatedOn,@ChargePointErrorCodeId, @ErrorInfo, @VendorId, @VendorErrorCode);
  79. """;
  80. bool isLocalConnection = conn is null;
  81. SqlConnection connection = isLocalConnection ? await sqlConnectionFactory.CreateAsync() : conn;
  82. var parameters = new DynamicParameters();
  83. parameters.Add("ConnectorId", data.connectorId, DbType.Int16);
  84. parameters.Add("Status", data.status, DbType.Int32);
  85. parameters.Add("ErrorInfo", data.errorInfo, DbType.String, size: 50);
  86. parameters.Add("VendorId", data.vendorId, DbType.String, size: 255);
  87. parameters.Add("CreatedOn", data.createdOn, DbType.DateTime);
  88. parameters.Add("VendorErrorCode", data.vendorErrorCode, DbType.String, size: 100);
  89. parameters.Add("ChargePointErrorCodeId", data.chargePointErrorCodeId, DbType.Int32);
  90. parameters.Add("ChargeBoxId", data.chargeBoxId, DbType.String, size: 50);
  91. await connection.ExecuteAsync(command, parameters, trans);
  92. if (isLocalConnection)
  93. {
  94. connection.Dispose();
  95. }
  96. }
  97. private async ValueTask<bool> GetTableExist(DateTime tableDateTime)
  98. {
  99. var tableName = GetTableName(tableDateTime);
  100. if (_existTables.Contains(tableName))
  101. {
  102. return true;
  103. }
  104. FormattableString checkTableSql = $"SELECT Count(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = {tableName}";
  105. using var db = await onlineRecordDbContextFactory.CreateDbContextAsync();
  106. var resultList = db.Database.SqlQuery<int>(checkTableSql)?.ToList();
  107. if (resultList is not null && resultList.Count > 0 && resultList[0] > 0)
  108. {
  109. _existTables.Enqueue(tableName);
  110. if (_existTables.Count > 30)
  111. {
  112. _existTables.TryDequeue(out _);
  113. }
  114. return true;
  115. }
  116. return false;
  117. }
  118. private async Task InsertWithStoredProcedure(InsertConnectorStatusParam param)
  119. {
  120. using var db = await onlineRecordDbContextFactory.CreateDbContextAsync();
  121. string sp = "[dbo].[uspInsertConnectorStatusRecord] @ChargeBoxId," +
  122. "@ConnectorId,@Status,@CreatedOn,@ChargePointErrorCodeId,@ErrorInfo,@VendorId,@VendorErrorCode";
  123. List<SqlParameter> parameter = new List<SqlParameter>();
  124. parameter.AddInsertConnectorStatusRecordSqlParameters(
  125. chargeBoxId: param.chargeBoxId
  126. , connectorId: param.connectorId
  127. , status: param.status
  128. , errorInfo: param.errorInfo
  129. , vendorId: param.vendorId
  130. , createdOn: param.createdOn
  131. , vendorErrorCode: param.vendorErrorCode
  132. , chargePointErrorCodeId: param.chargePointErrorCodeId );
  133. await db.Database.ExecuteSqlRawAsync(sp, parameter.ToArray());
  134. }
  135. private static string GetTableName(DateTime dateTime)
  136. => $"ConnectorStatusRecord{dateTime:yyMMdd}";
  137. }
  138. public record InsertConnectorStatusParam(string chargeBoxId, byte connectorId, int status, string errorInfo
  139. , string vendorId, DateTime createdOn, string vendorErrorCode, int chargePointErrorCodeId);