using System.Globalization; using Domain; using Npgsql; using NpgsqlTypes; namespace Infrastructure { public class PostgresRepository : IPostgresRepository { private readonly NpgsqlDataSource _dataSource; public PostgresRepository(string connectionString) { _dataSource = NpgsqlDataSource.Create(connectionString); } public async Task> ObterMedicoesAsync(string codigoSCDE, DateTime dataIni, DateTime dataFim, CancellationToken ct) { var existentes = new Dictionary<(string, double, int), Medicao>(); string sql = @" SELECT ponto, dia_num, minuto, origem, ativa_consumo, ativa_geracao, reativa_consumo, reativa_geracao FROM med_5min WHERE ponto = @ponto AND dia_num >= @data_ini AND dia_num <= @data_fim"; await using var command = _dataSource.CreateCommand(sql); command.Parameters.AddWithValue("ponto", codigoSCDE + "P"); command.Parameters.AddWithValue("data_ini", dataIni.ToOADate()); command.Parameters.AddWithValue("data_fim", dataFim.ToOADate()); await using var reader = await command.ExecuteReaderAsync(ct); while (await reader.ReadAsync(ct)) { var medicao = new Medicao( reader.GetString(0), reader.GetDouble(1), reader.GetInt32(2), reader.GetString(3), reader.IsDBNull(4) ? (double?)null : reader.GetDouble(4), reader.IsDBNull(5) ? (double?)null : reader.GetDouble(5), reader.IsDBNull(6) ? (double?)null : reader.GetDouble(6), reader.IsDBNull(7) ? (double?)null : reader.GetDouble(7) ); existentes[(medicao.Ponto, medicao.DiaNum, medicao.Minuto)] = medicao; } return existentes; } public async Task InserirMedicoesAsync(IEnumerable medicoes, CancellationToken ct) { await using var connection = await _dataSource.OpenConnectionAsync(ct); using var writer = connection.BeginBinaryImport( "COPY med_5min (origem, dia_num, minuto, ativa_consumo, ativa_geracao, reativa_consumo, reativa_geracao, ponto) FROM STDIN (FORMAT BINARY)"); foreach (var m in medicoes) { writer.StartRow(); writer.Write(m.Origem); writer.Write(m.DiaNum, NpgsqlDbType.Numeric); writer.Write(m.Minuto, NpgsqlDbType.Integer); writer.Write(m.AtivaConsumo, NpgsqlDbType.Numeric); writer.Write(m.AtivaGeracao, NpgsqlDbType.Numeric); writer.Write(m.ReativaConsumo, NpgsqlDbType.Numeric); writer.Write(m.ReativaGeracao, NpgsqlDbType.Numeric); writer.Write(m.Ponto); } await writer.CompleteAsync(); } public async Task AtualizarMedicoesAsync(IEnumerable medicoes, CancellationToken ct) { await using var connection = await _dataSource.OpenConnectionAsync(ct); using var batch = new NpgsqlBatch(connection); // Gerar os parâmetros dinamicamente, mantendo a abordagem parametrizada var valores = medicoes .Select((m, index) => new { Index = index, Ponto = m.Ponto, DiaNum = m.DiaNum, Minuto = m.Minuto, Origem = m.Origem, AtivaConsumo = m.AtivaConsumo, AtivaGeracao = m.AtivaGeracao, ReativaConsumo = m.ReativaConsumo, ReativaGeracao = m.ReativaGeracao }) .ToList(); var query = @" UPDATE med_5min SET origem = nv.origem, ativa_consumo = nv.ativa_consumo, ativa_geracao = nv.ativa_geracao, reativa_consumo = nv.reativa_consumo, reativa_geracao = nv.reativa_geracao FROM (VALUES"; // Adicionar os valores para o `VALUES` for (int i = 0; i < valores.Count; i++) { query += $" (@ponto_{i}, @dia_num_{i}, @minuto_{i}, @origem_{i}, " + $"@ativa_consumo_{i}, @ativa_geracao_{i}, @reativa_consumo_{i}, @reativa_geracao_{i})"; if (i < valores.Count - 1) { query += ", "; } } query += @") AS nv (ponto, dia_num, minuto, origem, ativa_consumo, ativa_geracao, reativa_consumo, reativa_geracao) WHERE med_5min.ponto = nv.ponto AND med_5min.dia_num = nv.dia_num AND med_5min.minuto = nv.minuto;"; // Agora, vamos adicionar os parâmetros à query var cmd = new NpgsqlBatchCommand(query); foreach (var valor in valores) { cmd.Parameters.AddWithValue($"ponto_{valor.Index}", valor.Ponto); cmd.Parameters.AddWithValue($"dia_num_{valor.Index}", valor.DiaNum); cmd.Parameters.AddWithValue($"minuto_{valor.Index}", valor.Minuto); cmd.Parameters.AddWithValue($"origem_{valor.Index}", valor.Origem); cmd.Parameters.AddWithValue($"ativa_consumo_{valor.Index}", valor.AtivaConsumo ?? (object)DBNull.Value); cmd.Parameters.AddWithValue($"ativa_geracao_{valor.Index}", valor.AtivaGeracao ?? (object)DBNull.Value); cmd.Parameters.AddWithValue($"reativa_consumo_{valor.Index}", valor.ReativaConsumo ?? (object)DBNull.Value); cmd.Parameters.AddWithValue($"reativa_geracao_{valor.Index}", valor.ReativaGeracao ?? (object)DBNull.Value); } batch.BatchCommands.Add(cmd); // Executar a query await batch.ExecuteNonQueryAsync(ct); } } }