Fix Worker
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -14,7 +14,7 @@ using System.Reflection;
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Api")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+18e6e8d3c0a378a172ad8e8afd31109673460717")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+5de9d6729c40c2a0d191760aa879b57282ff37e1")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Api")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Api")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
@@ -173,7 +173,6 @@ E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Diagnostics.Abstractions.dll
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Http.dll
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Options.ConfigurationExtensions.dll
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\buenos-aires-municipios.geojson
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.dll
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.AspNetCore.dll
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.Extensions.Hosting.dll
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["Dji\u002Bta/0e7zUKw3oe\u002BriV3kbWxZ93FP2z2QIYsHXTl4=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","42z\u002Bw0pajpMLFLNS29VoU/hUn9IzvZ/pVLNadS0rApY=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","ifGdmI/zx2hsc8PYkk8IWTP8aZ9RYmaQbfk383bAiYQ="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||
{"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["Dji\u002Bta/0e7zUKw3oe\u002BriV3kbWxZ93FP2z2QIYsHXTl4=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","GjNU75/P064gZSGHRGFQCzuU1j91Y6ISVIG9G9dpcs0=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","Oxph25v5ZpGJ3gq0\u002BdtskQ7kRY5YG8YA8z83gWvNxyw="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||
@@ -1 +1 @@
|
||||
{"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["Dji\u002Bta/0e7zUKw3oe\u002BriV3kbWxZ93FP2z2QIYsHXTl4=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","42z\u002Bw0pajpMLFLNS29VoU/hUn9IzvZ/pVLNadS0rApY=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","ifGdmI/zx2hsc8PYkk8IWTP8aZ9RYmaQbfk383bAiYQ="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||
{"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["Dji\u002Bta/0e7zUKw3oe\u002BriV3kbWxZ93FP2z2QIYsHXTl4=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","GjNU75/P064gZSGHRGFQCzuU1j91Y6ISVIG9G9dpcs0=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","Oxph25v5ZpGJ3gq0\u002BdtskQ7kRY5YG8YA8z83gWvNxyw="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||
@@ -13,7 +13,7 @@ using System.Reflection;
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Core")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+18e6e8d3c0a378a172ad8e8afd31109673460717")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+5de9d6729c40c2a0d191760aa879b57282ff37e1")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Core")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Core")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
@@ -27,6 +27,7 @@ public class EleccionesDbContext(DbContextOptions<EleccionesDbContext> options)
|
||||
// Precisión para los campos de porcentaje en EstadoRecuento
|
||||
modelBuilder.Entity<EstadoRecuento>(entity =>
|
||||
{
|
||||
entity.HasKey(e => new { e.AmbitoGeograficoId, e.CategoriaId });
|
||||
entity.Property(e => e.MesasTotalizadasPorcentaje).HasPrecision(5, 2);
|
||||
entity.Property(e => e.ParticipacionPorcentaje).HasPrecision(5, 2);
|
||||
entity.Property(e => e.VotosNulosPorcentaje).HasPrecision(18, 4);
|
||||
|
||||
@@ -8,9 +8,9 @@ public class EstadoRecuento
|
||||
{
|
||||
[Key]
|
||||
public int AmbitoGeograficoId { get; set; }
|
||||
public int CategoriaId { get; set; }
|
||||
[ForeignKey("AmbitoGeograficoId")]
|
||||
public AmbitoGeografico AmbitoGeografico { get; set; } = null!;
|
||||
|
||||
public DateTime FechaTotalizacion { get; set; }
|
||||
public int MesasEsperadas { get; set; }
|
||||
public int MesasTotalizadas { get; set; }
|
||||
|
||||
@@ -11,6 +11,8 @@ public class ResultadoVoto
|
||||
public long Id { get; set; }
|
||||
|
||||
public int AmbitoGeograficoId { get; set; }
|
||||
public int CategoriaId { get; set; }
|
||||
|
||||
[ForeignKey("AmbitoGeograficoId")]
|
||||
public AmbitoGeografico AmbitoGeografico { get; set; } = null!;
|
||||
|
||||
|
||||
370
Elecciones-Web/src/Elecciones.Database/Migrations/20250823135433_AddCategoriaIdToResultados.Designer.cs
generated
Normal file
370
Elecciones-Web/src/Elecciones.Database/Migrations/20250823135433_AddCategoriaIdToResultados.Designer.cs
generated
Normal file
@@ -0,0 +1,370 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Elecciones.Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Elecciones.Database.Migrations
|
||||
{
|
||||
[DbContext(typeof(EleccionesDbContext))]
|
||||
[Migration("20250823135433_AddCategoriaIdToResultados")]
|
||||
partial class AddCategoriaIdToResultados
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "9.0.8")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.AgrupacionPolitica", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("IdTelegrama")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Nombre")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("AgrupacionesPoliticas");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.AmbitoGeografico", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("CircuitoId")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DistritoId")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("EstablecimientoId")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("MesaId")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("MunicipioId")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("NivelId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Nombre")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("SeccionId")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("SeccionProvincialId")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("AmbitosGeograficos");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.CategoriaElectoral", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Nombre")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("Orden")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CategoriasElectorales");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.EstadoRecuento", b =>
|
||||
{
|
||||
b.Property<int>("AmbitoGeograficoId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("CategoriaId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("CantidadElectores")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("CantidadVotantes")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("FechaTotalizacion")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("MesasEsperadas")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MesasTotalizadas")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("MesasTotalizadasPorcentaje")
|
||||
.HasPrecision(5, 2)
|
||||
.HasColumnType("decimal(5,2)");
|
||||
|
||||
b.Property<decimal>("ParticipacionPorcentaje")
|
||||
.HasPrecision(5, 2)
|
||||
.HasColumnType("decimal(5,2)");
|
||||
|
||||
b.Property<long>("VotosEnBlanco")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<decimal>("VotosEnBlancoPorcentaje")
|
||||
.HasPrecision(18, 4)
|
||||
.HasColumnType("decimal(18,4)");
|
||||
|
||||
b.Property<long>("VotosNulos")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<decimal>("VotosNulosPorcentaje")
|
||||
.HasPrecision(18, 4)
|
||||
.HasColumnType("decimal(18,4)");
|
||||
|
||||
b.Property<long>("VotosRecurridos")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<decimal>("VotosRecurridosPorcentaje")
|
||||
.HasPrecision(18, 4)
|
||||
.HasColumnType("decimal(18,4)");
|
||||
|
||||
b.HasKey("AmbitoGeograficoId", "CategoriaId");
|
||||
|
||||
b.ToTable("EstadosRecuentos");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.EstadoRecuentoGeneral", b =>
|
||||
{
|
||||
b.Property<int>("AmbitoGeograficoId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("CategoriaId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("CantidadElectores")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("CantidadVotantes")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MesasEsperadas")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MesasTotalizadas")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("MesasTotalizadasPorcentaje")
|
||||
.HasPrecision(5, 2)
|
||||
.HasColumnType("decimal(5,2)");
|
||||
|
||||
b.Property<decimal>("ParticipacionPorcentaje")
|
||||
.HasPrecision(5, 2)
|
||||
.HasColumnType("decimal(5,2)");
|
||||
|
||||
b.HasKey("AmbitoGeograficoId", "CategoriaId");
|
||||
|
||||
b.HasIndex("CategoriaId");
|
||||
|
||||
b.ToTable("EstadosRecuentosGenerales");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.ProyeccionBanca", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("AgrupacionPoliticaId")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<int>("AmbitoGeograficoId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("NroBancas")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AgrupacionPoliticaId");
|
||||
|
||||
b.HasIndex("AmbitoGeograficoId");
|
||||
|
||||
b.ToTable("ProyeccionesBancas");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.ResultadoVoto", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<string>("AgrupacionPoliticaId")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<int>("AmbitoGeograficoId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<long>("CantidadVotos")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<int>("CategoriaId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("PorcentajeVotos")
|
||||
.HasPrecision(18, 4)
|
||||
.HasColumnType("decimal(18,4)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AgrupacionPoliticaId");
|
||||
|
||||
b.HasIndex("AmbitoGeograficoId", "AgrupacionPoliticaId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("ResultadosVotos");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.ResumenVoto", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("AgrupacionPoliticaId")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("AmbitoGeograficoId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<long>("Votos")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<decimal>("VotosPorcentaje")
|
||||
.HasPrecision(5, 2)
|
||||
.HasColumnType("decimal(5,2)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ResumenesVotos");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.Telegrama", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<int>("AmbitoGeograficoId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ContenidoBase64")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime>("FechaEscaneo")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime>("FechaTotalizacion")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Telegramas");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.EstadoRecuento", b =>
|
||||
{
|
||||
b.HasOne("Elecciones.Database.Entities.AmbitoGeografico", "AmbitoGeografico")
|
||||
.WithMany()
|
||||
.HasForeignKey("AmbitoGeograficoId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("AmbitoGeografico");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.EstadoRecuentoGeneral", b =>
|
||||
{
|
||||
b.HasOne("Elecciones.Database.Entities.CategoriaElectoral", "CategoriaElectoral")
|
||||
.WithMany()
|
||||
.HasForeignKey("CategoriaId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("CategoriaElectoral");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.ProyeccionBanca", b =>
|
||||
{
|
||||
b.HasOne("Elecciones.Database.Entities.AgrupacionPolitica", "AgrupacionPolitica")
|
||||
.WithMany()
|
||||
.HasForeignKey("AgrupacionPoliticaId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Elecciones.Database.Entities.AmbitoGeografico", "AmbitoGeografico")
|
||||
.WithMany()
|
||||
.HasForeignKey("AmbitoGeograficoId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("AgrupacionPolitica");
|
||||
|
||||
b.Navigation("AmbitoGeografico");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.ResultadoVoto", b =>
|
||||
{
|
||||
b.HasOne("Elecciones.Database.Entities.AgrupacionPolitica", "AgrupacionPolitica")
|
||||
.WithMany()
|
||||
.HasForeignKey("AgrupacionPoliticaId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Elecciones.Database.Entities.AmbitoGeografico", "AmbitoGeografico")
|
||||
.WithMany()
|
||||
.HasForeignKey("AmbitoGeograficoId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("AgrupacionPolitica");
|
||||
|
||||
b.Navigation("AmbitoGeografico");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Elecciones.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddCategoriaIdToResultados : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_EstadosRecuentos",
|
||||
table: "EstadosRecuentos");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "CategoriaId",
|
||||
table: "ResultadosVotos",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "CategoriaId",
|
||||
table: "EstadosRecuentos",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_EstadosRecuentos",
|
||||
table: "EstadosRecuentos",
|
||||
columns: new[] { "AmbitoGeograficoId", "CategoriaId" });
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_EstadosRecuentos",
|
||||
table: "EstadosRecuentos");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "CategoriaId",
|
||||
table: "ResultadosVotos");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "CategoriaId",
|
||||
table: "EstadosRecuentos");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_EstadosRecuentos",
|
||||
table: "EstadosRecuentos",
|
||||
column: "AmbitoGeograficoId");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,6 +103,9 @@ namespace Elecciones.Database.Migrations
|
||||
b.Property<int>("AmbitoGeograficoId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("CategoriaId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("CantidadElectores")
|
||||
.HasColumnType("int");
|
||||
|
||||
@@ -147,7 +150,7 @@ namespace Elecciones.Database.Migrations
|
||||
.HasPrecision(18, 4)
|
||||
.HasColumnType("decimal(18,4)");
|
||||
|
||||
b.HasKey("AmbitoGeograficoId");
|
||||
b.HasKey("AmbitoGeograficoId", "CategoriaId");
|
||||
|
||||
b.ToTable("EstadosRecuentos");
|
||||
});
|
||||
@@ -232,6 +235,9 @@ namespace Elecciones.Database.Migrations
|
||||
b.Property<long>("CantidadVotos")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<int>("CategoriaId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("PorcentajeVotos")
|
||||
.HasPrecision(18, 4)
|
||||
.HasColumnType("decimal(18,4)");
|
||||
|
||||
@@ -13,7 +13,7 @@ using System.Reflection;
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Database")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+18e6e8d3c0a378a172ad8e8afd31109673460717")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+5de9d6729c40c2a0d191760aa879b57282ff37e1")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Database")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Database")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -13,7 +13,7 @@ using System.Reflection;
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Infrastructure")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+18e6e8d3c0a378a172ad8e8afd31109673460717")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+5de9d6729c40c2a0d191760aa879b57282ff37e1")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Infrastructure")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Infrastructure")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
@@ -13,4 +13,3 @@ E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Infrastructure\obj\Debug\net9.0
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Infrastructure\obj\Debug\net9.0\refint\Elecciones.Infrastructure.dll
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Infrastructure\obj\Debug\net9.0\Elecciones.Infrastructure.pdb
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Infrastructure\obj\Debug\net9.0\ref\Elecciones.Infrastructure.dll
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Infrastructure\bin\Debug\net9.0\buenos-aires-municipios.geojson
|
||||
|
||||
@@ -11,38 +11,35 @@ public class CriticalDataWorker : BackgroundService
|
||||
private readonly ILogger<CriticalDataWorker> _logger;
|
||||
private readonly SharedTokenService _tokenService;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IElectoralApiService _apiService; // <-- DEPENDENCIA AÑADIDA
|
||||
private readonly IElectoralApiService _apiService;
|
||||
|
||||
// Inyectamos IElectoralApiService en el constructor
|
||||
public CriticalDataWorker(
|
||||
ILogger<CriticalDataWorker> logger,
|
||||
SharedTokenService tokenService,
|
||||
IServiceProvider serviceProvider,
|
||||
IElectoralApiService apiService) // <-- PARÁMETRO AÑADIDO
|
||||
IElectoralApiService apiService)
|
||||
{
|
||||
_logger = logger;
|
||||
_tokenService = tokenService;
|
||||
_serviceProvider = serviceProvider;
|
||||
_apiService = apiService; // <-- ASIGNACIÓN AÑADIDA
|
||||
_apiService = apiService;
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
_logger.LogInformation("Worker de Datos Críticos iniciado.");
|
||||
|
||||
// Damos tiempo a la sincronización inicial del otro worker para que se complete.
|
||||
try
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromMinutes(2), stoppingToken);
|
||||
}
|
||||
catch (TaskCanceledException) { return; } // Salir si la app se apaga durante la espera inicial
|
||||
catch (TaskCanceledException) { return; }
|
||||
|
||||
int cicloContador = 0;
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
var cicloInicio = DateTime.UtcNow;
|
||||
cicloContador++;
|
||||
|
||||
_logger.LogInformation("--- Iniciando Ciclo de Datos Críticos #{ciclo} ---", cicloContador);
|
||||
|
||||
var authToken = await _tokenService.GetValidAuthTokenAsync(stoppingToken);
|
||||
@@ -68,153 +65,73 @@ public class CriticalDataWorker : BackgroundService
|
||||
{
|
||||
await Task.Delay(tiempoDeEspera, stoppingToken);
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch (TaskCanceledException) { break; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sondea los resultados electorales para todos los municipios/partidos de forma optimizada.
|
||||
/// Utiliza paralelismo controlado para ejecutar múltiples peticiones a la API simultáneamente
|
||||
/// sin sobrecargar la red, y luego guarda todos los resultados en la base de datos de forma masiva.
|
||||
/// </summary>
|
||||
/// <param name="authToken">El token de autenticación válido para la sesión.</param>
|
||||
/// <param name="stoppingToken">El token de cancelación para detener la operación.</param>
|
||||
private async Task SondearResultadosMunicipalesAsync(string authToken, CancellationToken stoppingToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
// PASO 1: Preparar el DbContext y los datos necesarios.
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<EleccionesDbContext>();
|
||||
|
||||
// Obtenemos de nuestra BD local la lista de todos los partidos (NivelId=30) que necesitamos consultar.
|
||||
var municipiosASondear = await dbContext.AmbitosGeograficos
|
||||
.AsNoTracking()
|
||||
.Where(a => a.NivelId == 30 && a.DistritoId != null && a.SeccionId != null)
|
||||
.Select(a => new { a.Id, a.Nombre, a.MunicipioId, a.SeccionId, a.DistritoId })
|
||||
.ToListAsync(stoppingToken);
|
||||
|
||||
if (!municipiosASondear.Any())
|
||||
{
|
||||
_logger.LogWarning("No se encontraron Partidos (NivelId 30) en la BD para sondear resultados.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Obtenemos la categoría "CONCEJALES", ya que los resultados municipales aplican a esta.
|
||||
var categoriaConcejales = await dbContext.CategoriasElectorales
|
||||
var todasLasCategorias = await dbContext.CategoriasElectorales
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(c => c.Nombre.Contains("CONCEJALES"), stoppingToken);
|
||||
.ToListAsync(stoppingToken);
|
||||
|
||||
if (categoriaConcejales == null)
|
||||
if (!municipiosASondear.Any() || !todasLasCategorias.Any())
|
||||
{
|
||||
_logger.LogWarning("No se encontró la categoría 'CONCEJALES'. Omitiendo sondeo de resultados municipales.");
|
||||
_logger.LogWarning("No se encontraron Partidos (NivelId 30) o Categorías para sondear resultados.");
|
||||
return;
|
||||
}
|
||||
|
||||
// PASO 2: Ejecutar las consultas a la API con paralelismo controlado.
|
||||
_logger.LogInformation("Iniciando sondeo de resultados para {m} municipios y {c} categorías...", municipiosASondear.Count, todasLasCategorias.Count);
|
||||
|
||||
// Definimos cuántas peticiones queremos que se ejecuten simultáneamente.
|
||||
// Un valor entre 8 y 16 es generalmente seguro y ofrece una gran mejora de velocidad.
|
||||
const int GRADO_DE_PARALELISMO = 3;
|
||||
// Creamos un semáforo que actuará como un "control de acceso" con 10 pases libres.
|
||||
var semaforo = new SemaphoreSlim(GRADO_DE_PARALELISMO);
|
||||
|
||||
// Usamos un ConcurrentDictionary para almacenar los resultados. A diferencia de un Dictionary normal,
|
||||
// este permite que múltiples tareas escriban en él al mismo tiempo sin conflictos.
|
||||
var resultadosPorId = new ConcurrentDictionary<int, Elecciones.Core.DTOs.ResultadosDto>();
|
||||
|
||||
_logger.LogInformation("Iniciando sondeo de resultados para {count} municipios con un paralelismo de {degree}...", municipiosASondear.Count, GRADO_DE_PARALELISMO);
|
||||
|
||||
// Creamos una lista de tareas (Tasks), una por cada municipio a consultar.
|
||||
// El método .Select() no ejecuta las tareas todavía, solo las prepara.
|
||||
var tareas = municipiosASondear.Select(async municipio =>
|
||||
foreach (var municipio in municipiosASondear)
|
||||
{
|
||||
// Cada tarea debe "pedir permiso" al semáforo antes de ejecutarse.
|
||||
// Si ya hay 10 tareas en ejecución, esta línea esperará hasta que una termine.
|
||||
await semaforo.WaitAsync(stoppingToken);
|
||||
try
|
||||
{
|
||||
// Una vez que obtiene el permiso, ejecuta la petición a la API.
|
||||
var resultados = await _apiService.GetResultadosAsync(
|
||||
authToken, municipio.DistritoId!, municipio.SeccionId!, null, categoriaConcejales.Id
|
||||
);
|
||||
if (stoppingToken.IsCancellationRequested) break;
|
||||
|
||||
var tareasCategoria = todasLasCategorias.Select(async categoria =>
|
||||
{
|
||||
var resultados = await _apiService.GetResultadosAsync(authToken, municipio.DistritoId!, municipio.SeccionId!, null, categoria.Id);
|
||||
|
||||
// Si la API devuelve datos válidos...
|
||||
if (resultados != null)
|
||||
{
|
||||
// ...los guardamos en el diccionario concurrente.
|
||||
resultadosPorId[municipio.Id] = resultados;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// ¡CRUCIAL! Liberamos el pase del semáforo, permitiendo que la siguiente
|
||||
// tarea en espera pueda comenzar su ejecución.
|
||||
semaforo.Release();
|
||||
// Añadir un pequeño retraso aleatorio para no parecer un robot
|
||||
await Task.Delay(TimeSpan.FromMilliseconds(new Random().Next(50, 251)), stoppingToken);
|
||||
using var innerScope = _serviceProvider.CreateScope();
|
||||
var innerDbContext = innerScope.ServiceProvider.GetRequiredService<EleccionesDbContext>();
|
||||
|
||||
// --- LLAMADA CORRECTA ---
|
||||
await GuardarResultadosDeAmbitoAsync(innerDbContext, municipio.Id, categoria.Id, resultados, stoppingToken);
|
||||
}
|
||||
});
|
||||
|
||||
// Ahora sí, ejecutamos todas las tareas preparadas en paralelo y esperamos a que todas terminen.
|
||||
await Task.WhenAll(tareas);
|
||||
|
||||
// PASO 3: Guardar los resultados en la base de datos.
|
||||
// Solo procedemos si recolectamos al menos un resultado válido.
|
||||
if (resultadosPorId.Any())
|
||||
{
|
||||
// Llamamos a nuestro método de guardado masivo y optimizado, pasándole todos los resultados
|
||||
// recolectados para que los inserte en una única y eficiente transacción.
|
||||
await GuardarResultadosDeMunicipiosAsync(dbContext, resultadosPorId.ToDictionary(kv => kv.Key, kv => kv.Value), stoppingToken);
|
||||
await Task.WhenAll(tareasCategoria);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Capturamos cualquier error inesperado en el proceso para que el worker no se detenga.
|
||||
_logger.LogError(ex, "Ocurrió un error inesperado durante el sondeo de resultados municipales.");
|
||||
}
|
||||
}
|
||||
|
||||
/// Realiza una operación "Upsert" (Update o Insert) de forma masiva y optimizada.
|
||||
/// Este método es llamado por SondearResultadosMunicipalesAsync.
|
||||
/// </summary>
|
||||
private async Task GuardarResultadosDeMunicipiosAsync(
|
||||
EleccionesDbContext dbContext,
|
||||
Dictionary<int, Elecciones.Core.DTOs.ResultadosDto> todosLosResultados,
|
||||
CancellationToken stoppingToken) // <-- PARÁMETRO AÑADIDO
|
||||
private async Task GuardarResultadosDeAmbitoAsync(
|
||||
EleccionesDbContext dbContext, int ambitoId, int categoriaId,
|
||||
Elecciones.Core.DTOs.ResultadosDto resultadosDto, CancellationToken stoppingToken)
|
||||
{
|
||||
// Obtenemos los IDs de todos los ámbitos que vamos a actualizar.
|
||||
var ambitoIds = todosLosResultados.Keys;
|
||||
var estadoRecuento = await dbContext.EstadosRecuentos.FindAsync(new object[] { ambitoId, categoriaId }, stoppingToken);
|
||||
|
||||
// --- OPTIMIZACIÓN 1: Cargar todos los datos existentes en memoria UNA SOLA VEZ ---
|
||||
var estadosRecuentoExistentes = await dbContext.EstadosRecuentos
|
||||
.Where(e => ambitoIds.Contains(e.AmbitoGeograficoId))
|
||||
.ToDictionaryAsync(e => e.AmbitoGeograficoId, stoppingToken);
|
||||
|
||||
var resultadosVotosExistentes = await dbContext.ResultadosVotos
|
||||
.Where(rv => ambitoIds.Contains(rv.AmbitoGeograficoId))
|
||||
.GroupBy(rv => rv.AmbitoGeograficoId)
|
||||
.ToDictionaryAsync(g => g.Key, g => g.ToDictionary(item => item.AgrupacionPoliticaId), stoppingToken);
|
||||
|
||||
_logger.LogInformation("Procesando en memoria los resultados de {count} municipios.", todosLosResultados.Count);
|
||||
|
||||
// --- OPTIMIZACIÓN 2: Procesar todo en memoria ---
|
||||
foreach (var kvp in todosLosResultados)
|
||||
if (estadoRecuento == null)
|
||||
{
|
||||
var ambitoId = kvp.Key;
|
||||
var resultadosDto = kvp.Value;
|
||||
|
||||
// Lógica Upsert para EstadoRecuento
|
||||
if (!estadosRecuentoExistentes.TryGetValue(ambitoId, out var estadoRecuento))
|
||||
{
|
||||
estadoRecuento = new EstadoRecuento { AmbitoGeograficoId = ambitoId };
|
||||
estadoRecuento = new EstadoRecuento { AmbitoGeograficoId = ambitoId, CategoriaId = categoriaId };
|
||||
dbContext.EstadosRecuentos.Add(estadoRecuento);
|
||||
}
|
||||
|
||||
// Mapeo completo de propiedades para EstadoRecuento
|
||||
estadoRecuento.FechaTotalizacion = DateTime.Parse(resultadosDto.FechaTotalizacion).ToUniversalTime();
|
||||
estadoRecuento.MesasEsperadas = resultadosDto.EstadoRecuento.MesasEsperadas;
|
||||
estadoRecuento.MesasTotalizadas = resultadosDto.EstadoRecuento.MesasTotalizadas;
|
||||
@@ -233,21 +150,21 @@ public class CriticalDataWorker : BackgroundService
|
||||
estadoRecuento.VotosRecurridosPorcentaje = resultadosDto.ValoresTotalizadosOtros.VotosRecurridosPorcentaje;
|
||||
}
|
||||
|
||||
// Lógica Upsert para ResultadosVotos
|
||||
var votosDeAmbitoExistentes = resultadosVotosExistentes.GetValueOrDefault(ambitoId);
|
||||
foreach (var votoPositivoDto in resultadosDto.ValoresTotalizadosPositivos)
|
||||
{
|
||||
ResultadoVoto? resultadoVoto = null;
|
||||
if (votosDeAmbitoExistentes != null)
|
||||
{
|
||||
votosDeAmbitoExistentes.TryGetValue(votoPositivoDto.IdAgrupacion, out resultadoVoto);
|
||||
}
|
||||
var resultadoVoto = await dbContext.ResultadosVotos.FirstOrDefaultAsync(
|
||||
rv => rv.AmbitoGeograficoId == ambitoId &&
|
||||
rv.CategoriaId == categoriaId &&
|
||||
rv.AgrupacionPoliticaId == votoPositivoDto.IdAgrupacion,
|
||||
stoppingToken
|
||||
);
|
||||
|
||||
if (resultadoVoto == null)
|
||||
{
|
||||
resultadoVoto = new ResultadoVoto
|
||||
{
|
||||
AmbitoGeograficoId = ambitoId,
|
||||
CategoriaId = categoriaId,
|
||||
AgrupacionPoliticaId = votoPositivoDto.IdAgrupacion
|
||||
};
|
||||
dbContext.ResultadosVotos.Add(resultadoVoto);
|
||||
@@ -255,13 +172,15 @@ public class CriticalDataWorker : BackgroundService
|
||||
resultadoVoto.CantidadVotos = votoPositivoDto.Votos;
|
||||
resultadoVoto.PorcentajeVotos = votoPositivoDto.VotosPorcentaje;
|
||||
}
|
||||
}
|
||||
|
||||
// --- OPTIMIZACIÓN 3: Guardar todos los cambios en UNA SOLA TRANSACCIÓN ---
|
||||
_logger.LogInformation("Guardando todos los cambios de resultados municipales en la base de datos...");
|
||||
// Ahora 'stoppingToken' es reconocido aquí
|
||||
try
|
||||
{
|
||||
await dbContext.SaveChangesAsync(stoppingToken);
|
||||
_logger.LogInformation("Guardado completado.");
|
||||
}
|
||||
catch (DbUpdateException ex)
|
||||
{
|
||||
_logger.LogError(ex, "DbUpdateException al guardar resultados para AmbitoId {ambitoId} y CategoriaId {categoriaId}", ambitoId, categoriaId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -420,11 +339,4 @@ public class CriticalDataWorker : BackgroundService
|
||||
_logger.LogError(ex, "Ocurrió un error CRÍTICO en el sondeo de Estado Recuento General.");
|
||||
}
|
||||
}
|
||||
|
||||
// Pega aquí los métodos:
|
||||
// - SondearResultadosMunicipalesAsync
|
||||
// - GuardarResultadosDeMunicipiosAsync
|
||||
// - SondearResumenProvincialAsync
|
||||
// - SondearEstadoRecuentoGeneralAsync
|
||||
// (Estos métodos necesitan IServiceProvider y SharedTokenService, que ya están inyectados)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user