diff --git a/Backend/Backend.csproj b/Backend/Backend.csproj
index a2c7635..22f8876 100644
--- a/Backend/Backend.csproj
+++ b/Backend/Backend.csproj
@@ -14,12 +14,19 @@
PreserveNewest
+
+ PreserveNewest
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/Backend/Program.cs b/Backend/Program.cs
index 7a2f512..0ea0988 100644
--- a/Backend/Program.cs
+++ b/Backend/Program.cs
@@ -18,7 +18,6 @@ static async Task Main(string[] args)
// Main scope of application
using (var scope = host.Services.CreateScope())
{
- //TODO this is just temp, delete later
var services = scope.ServiceProvider;
var dataProcessingService = services.GetRequiredService();
diff --git a/Backend/Services/DataProcessingService.cs b/Backend/Services/DataProcessingService.cs
index 648a262..e0ad03f 100644
--- a/Backend/Services/DataProcessingService.cs
+++ b/Backend/Services/DataProcessingService.cs
@@ -1,3 +1,4 @@
+using System.Diagnostics;
using Backend.Clients;
using Backend.Mappers;
using HouseScout.Model;
@@ -21,15 +22,39 @@ HouseScoutContext context
public async Task ProcessData()
{
+ var existingEstates = _context.Estates.ToList();
+
+ var fetchedEstates = new List();
+
foreach (var kvp in _clientsAndMappers)
{
IClient client = kvp.Key;
IMapper mapper = kvp.Value;
var data = await client.FetchDataAsync();
- var mappedData = mapper.MapResponseToModel(data);
- _context.Estates.AddRange(mappedData);
- await _context.SaveChangesAsync();
+ fetchedEstates.AddRange(mapper.MapResponseToModel(data));
+ }
+
+ var fetchedEstatesSet = new HashSet(fetchedEstates.Select(fe => fe.ApiId));
+ var existingEstatesSet = new HashSet(existingEstates.Select(fe => fe.ApiId));
+
+ var estatesToAdd = fetchedEstates
+ .Where(fe => !existingEstatesSet.Contains(fe.ApiId))
+ .ToList();
+
+ var estatesToRemove = existingEstates
+ .Where(ee => !fetchedEstatesSet.Contains(ee.ApiId))
+ .ToList();
+
+ if (estatesToAdd.Any())
+ {
+ await _context.Estates.AddRangeAsync(estatesToAdd);
+ }
+
+ if (estatesToRemove.Any())
+ {
+ _context.Estates.RemoveRange(estatesToRemove);
}
+ await _context.SaveChangesAsync();
}
}
diff --git a/SharedDependencies/Migrations/20240901114150_InitialCreate.Designer.cs b/SharedDependencies/Migrations/20240901114150_InitialCreate.Designer.cs
new file mode 100644
index 0000000..d22c1c2
--- /dev/null
+++ b/SharedDependencies/Migrations/20240901114150_InitialCreate.Designer.cs
@@ -0,0 +1,69 @@
+//
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using SharedDependencies.Model;
+
+#nullable disable
+
+namespace SharedDependencies.Migrations
+{
+ [DbContext(typeof(HouseScoutContext))]
+ [Migration("20240901114150_InitialCreate")]
+ partial class InitialCreate
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.8")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("HouseScout.Model.Estate", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Address")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ApiId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ApiType")
+ .HasColumnType("integer");
+
+ b.Property("EstateType")
+ .HasColumnType("integer");
+
+ b.Property("Link")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("OfferType")
+ .HasColumnType("integer");
+
+ b.Property("Price")
+ .HasColumnType("numeric");
+
+ b.Property("Surface")
+ .HasColumnType("double precision");
+
+ b.HasKey("Id");
+
+ b.ToTable("Estates");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/SharedDependencies/Migrations/20240901114150_InitialCreate.cs b/SharedDependencies/Migrations/20240901114150_InitialCreate.cs
new file mode 100644
index 0000000..0cf94ee
--- /dev/null
+++ b/SharedDependencies/Migrations/20240901114150_InitialCreate.cs
@@ -0,0 +1,46 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace SharedDependencies.Migrations
+{
+ ///
+ public partial class InitialCreate : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "Estates",
+ columns: table => new
+ {
+ Id = table
+ .Column(type: "integer", nullable: false)
+ .Annotation(
+ "Npgsql:ValueGenerationStrategy",
+ NpgsqlValueGenerationStrategy.IdentityByDefaultColumn
+ ),
+ ApiType = table.Column(type: "integer", nullable: false),
+ ApiId = table.Column(type: "text", nullable: false),
+ Address = table.Column(type: "text", nullable: false),
+ Price = table.Column(type: "numeric", nullable: false),
+ Link = table.Column(type: "text", nullable: false),
+ Surface = table.Column(type: "double precision", nullable: false),
+ EstateType = table.Column(type: "integer", nullable: false),
+ OfferType = table.Column(type: "integer", nullable: false),
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Estates", x => x.Id);
+ }
+ );
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(name: "Estates");
+ }
+ }
+}
diff --git a/SharedDependencies/Migrations/HouseScoutContextModelSnapshot.cs b/SharedDependencies/Migrations/HouseScoutContextModelSnapshot.cs
new file mode 100644
index 0000000..e100372
--- /dev/null
+++ b/SharedDependencies/Migrations/HouseScoutContextModelSnapshot.cs
@@ -0,0 +1,66 @@
+//
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using SharedDependencies.Model;
+
+#nullable disable
+
+namespace SharedDependencies.Migrations
+{
+ [DbContext(typeof(HouseScoutContext))]
+ partial class HouseScoutContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.8")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("HouseScout.Model.Estate", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Address")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ApiId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ApiType")
+ .HasColumnType("integer");
+
+ b.Property("EstateType")
+ .HasColumnType("integer");
+
+ b.Property("Link")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("OfferType")
+ .HasColumnType("integer");
+
+ b.Property("Price")
+ .HasColumnType("numeric");
+
+ b.Property("Surface")
+ .HasColumnType("double precision");
+
+ b.HasKey("Id");
+
+ b.ToTable("Estates");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}