From b390d4a1080590f817a8bb814bac2305aa0efd10 Mon Sep 17 00:00:00 2001 From: Reimar Date: Wed, 2 Apr 2025 13:36:51 +0200 Subject: [PATCH] Optimize query to fetch logs within date period --- backend/Api/BusinessLogic/DeviceLogic.cs | 14 +- backend/Api/DBAccess/DBAccess.cs | 15 +- backend/Api/DBAccess/DBContext.cs | 3 + ...02113522_ChangeModelsNamespace.Designer.cs | 140 ++++++++++++++++++ .../20250402113522_ChangeModelsNamespace.cs | 59 ++++++++ .../Api/Migrations/DBContextModelSnapshot.cs | 20 +-- backend/Api/Models/TemperatureLogs.cs | 2 + 7 files changed, 224 insertions(+), 29 deletions(-) create mode 100644 backend/Api/Migrations/20250402113522_ChangeModelsNamespace.Designer.cs create mode 100644 backend/Api/Migrations/20250402113522_ChangeModelsNamespace.cs diff --git a/backend/Api/BusinessLogic/DeviceLogic.cs b/backend/Api/BusinessLogic/DeviceLogic.cs index dc55b6c..da5e867 100644 --- a/backend/Api/BusinessLogic/DeviceLogic.cs +++ b/backend/Api/BusinessLogic/DeviceLogic.cs @@ -76,19 +76,9 @@ namespace Api.BusinessLogic if (device == null) { return new ConflictObjectResult(new { message = "Could not find device" }); } - var logs = await _dbAccess.ReadLogs(deviceId); + var logs = await _dbAccess.ReadLogs(deviceId, dateTimeRange); - if (logs.Count == 0) { return new ConflictObjectResult(new { message = "Could not find any logs connected to the device" }); } - - if (dateTimeRange.DateTimeStart == dateTimeRange.DateTimeEnd) { return new OkObjectResult(logs); } - - List rangedLogs = new List(); - foreach (var log in logs) - { - if (log.Date >= dateTimeRange.DateTimeStart && log.Date <= dateTimeRange.DateTimeEnd) { rangedLogs.Add(log); } - } - - return new OkObjectResult(rangedLogs); + return new OkObjectResult(logs); } /// diff --git a/backend/Api/DBAccess/DBAccess.cs b/backend/Api/DBAccess/DBAccess.cs index 6885970..3e9dd6a 100644 --- a/backend/Api/DBAccess/DBAccess.cs +++ b/backend/Api/DBAccess/DBAccess.cs @@ -311,16 +311,15 @@ namespace Api.DBAccess /// Returns the logs from the device /// /// Has the id for the device that the los belong too + /// Return only logs within the specified datetime range /// - public async Task> ReadLogs(int deviceId) + public async Task> ReadLogs(int deviceId, DateTimeRange range) { - var device = await _context.Devices.Include(d => d.Logs).FirstOrDefaultAsync(d => d.Id == deviceId); - - if (device == null || device.Logs == null) { return new List(); } - - var logs = device.Logs; - - return logs; + return _context.TemperatureLogs + .Where(log => log.DeviceId == deviceId) + .Where(log => log.Date > range.DateTimeStart) + .Where(log => log.Date < range.DateTimeEnd) + .ToList(); } /// diff --git a/backend/Api/DBAccess/DBContext.cs b/backend/Api/DBAccess/DBContext.cs index 7f66cdb..df6600e 100644 --- a/backend/Api/DBAccess/DBContext.cs +++ b/backend/Api/DBAccess/DBContext.cs @@ -1,4 +1,5 @@ using Microsoft.EntityFrameworkCore; +using Api.Models; using Api.Models.Users; using Api.Models.Devices; @@ -10,6 +11,8 @@ namespace Api public DbSet Devices { get; set; } + public DbSet TemperatureLogs { get; set; } + public DBContext(DbContextOptions options) : base(options) { } } } diff --git a/backend/Api/Migrations/20250402113522_ChangeModelsNamespace.Designer.cs b/backend/Api/Migrations/20250402113522_ChangeModelsNamespace.Designer.cs new file mode 100644 index 0000000..1000ce4 --- /dev/null +++ b/backend/Api/Migrations/20250402113522_ChangeModelsNamespace.Designer.cs @@ -0,0 +1,140 @@ +// +using System; +using Api; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Api.Migrations +{ + [DbContext(typeof(DBContext))] + [Migration("20250402113522_ChangeModelsNamespace")] + partial class ChangeModelsNamespace + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "9.0.3"); + + modelBuilder.Entity("Api.Models.Devices.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ReferenceId") + .HasColumnType("TEXT"); + + b.Property("TempHigh") + .HasColumnType("REAL"); + + b.Property("TempLow") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Api.Models.TemperatureLogs", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Date") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .HasColumnType("INTEGER"); + + b.Property("TempHigh") + .HasColumnType("REAL"); + + b.Property("TempLow") + .HasColumnType("REAL"); + + b.Property("Temperature") + .HasColumnType("REAL"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.ToTable("TemperatureLogs"); + }); + + modelBuilder.Entity("Api.Models.Users.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Email") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Password") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RefreshToken") + .HasColumnType("TEXT"); + + b.Property("RefreshTokenExpiresAt") + .HasColumnType("TEXT"); + + b.Property("Salt") + .HasColumnType("TEXT"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Api.Models.Devices.Device", b => + { + b.HasOne("Api.Models.Users.User", null) + .WithMany("Devices") + .HasForeignKey("UserId"); + }); + + modelBuilder.Entity("Api.Models.TemperatureLogs", b => + { + b.HasOne("Api.Models.Devices.Device", null) + .WithMany("Logs") + .HasForeignKey("DeviceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Api.Models.Devices.Device", b => + { + b.Navigation("Logs"); + }); + + modelBuilder.Entity("Api.Models.Users.User", b => + { + b.Navigation("Devices"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/backend/Api/Migrations/20250402113522_ChangeModelsNamespace.cs b/backend/Api/Migrations/20250402113522_ChangeModelsNamespace.cs new file mode 100644 index 0000000..671a740 --- /dev/null +++ b/backend/Api/Migrations/20250402113522_ChangeModelsNamespace.cs @@ -0,0 +1,59 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Api.Migrations +{ + /// + public partial class ChangeModelsNamespace : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_TemperatureLogs_Devices_DeviceId", + table: "TemperatureLogs"); + + migrationBuilder.AlterColumn( + name: "DeviceId", + table: "TemperatureLogs", + type: "INTEGER", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AddForeignKey( + name: "FK_TemperatureLogs_Devices_DeviceId", + table: "TemperatureLogs", + column: "DeviceId", + principalTable: "Devices", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_TemperatureLogs_Devices_DeviceId", + table: "TemperatureLogs"); + + migrationBuilder.AlterColumn( + name: "DeviceId", + table: "TemperatureLogs", + type: "INTEGER", + nullable: true, + oldClrType: typeof(int), + oldType: "INTEGER"); + + migrationBuilder.AddForeignKey( + name: "FK_TemperatureLogs_Devices_DeviceId", + table: "TemperatureLogs", + column: "DeviceId", + principalTable: "Devices", + principalColumn: "Id"); + } + } +} diff --git a/backend/Api/Migrations/DBContextModelSnapshot.cs b/backend/Api/Migrations/DBContextModelSnapshot.cs index 6d96bdd..ebab47a 100644 --- a/backend/Api/Migrations/DBContextModelSnapshot.cs +++ b/backend/Api/Migrations/DBContextModelSnapshot.cs @@ -17,7 +17,7 @@ namespace Api.Migrations #pragma warning disable 612, 618 modelBuilder.HasAnnotation("ProductVersion", "9.0.3"); - modelBuilder.Entity("Api.Models.Device", b => + modelBuilder.Entity("Api.Models.Devices.Device", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -55,7 +55,7 @@ namespace Api.Migrations b.Property("Date") .HasColumnType("TEXT"); - b.Property("DeviceId") + b.Property("DeviceId") .HasColumnType("INTEGER"); b.Property("TempHigh") @@ -74,7 +74,7 @@ namespace Api.Migrations b.ToTable("TemperatureLogs"); }); - modelBuilder.Entity("Api.Models.User", b => + modelBuilder.Entity("Api.Models.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -106,26 +106,28 @@ namespace Api.Migrations b.ToTable("Users"); }); - modelBuilder.Entity("Api.Models.Device", b => + modelBuilder.Entity("Api.Models.Devices.Device", b => { - b.HasOne("Api.Models.User", null) + b.HasOne("Api.Models.Users.User", null) .WithMany("Devices") .HasForeignKey("UserId"); }); modelBuilder.Entity("Api.Models.TemperatureLogs", b => { - b.HasOne("Api.Models.Device", null) + b.HasOne("Api.Models.Devices.Device", null) .WithMany("Logs") - .HasForeignKey("DeviceId"); + .HasForeignKey("DeviceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); - modelBuilder.Entity("Api.Models.Device", b => + modelBuilder.Entity("Api.Models.Devices.Device", b => { b.Navigation("Logs"); }); - modelBuilder.Entity("Api.Models.User", b => + modelBuilder.Entity("Api.Models.Users.User", b => { b.Navigation("Devices"); }); diff --git a/backend/Api/Models/TemperatureLogs.cs b/backend/Api/Models/TemperatureLogs.cs index 16911a2..9216987 100644 --- a/backend/Api/Models/TemperatureLogs.cs +++ b/backend/Api/Models/TemperatureLogs.cs @@ -4,6 +4,8 @@ { public int Id { get; set; } + public int DeviceId { get; set; } + public double Temperature { get; set; } public DateTime Date { get; set; }