diff --git a/SoilMoistureAPI/Controllers/DeviceController.cs b/SoilMoistureAPI/Controllers/DeviceController.cs index fb0dd96..27d6543 100644 --- a/SoilMoistureAPI/Controllers/DeviceController.cs +++ b/SoilMoistureAPI/Controllers/DeviceController.cs @@ -10,16 +10,16 @@ namespace SoilMoistureAPI.Controllers [ApiController] public class DeviceController : ControllerBase { - private readonly SoilMoistureContext _context; + private readonly SoilMoistureFlatContext _context; - public DeviceController(SoilMoistureContext context) + public DeviceController(SoilMoistureFlatContext context) { _context = context; } // POST: api/Device [HttpPost] - public async Task> CreateDevice(Device device) + public async Task> CreateDevice(SoilMoistureFlat device) { if (device == null || string.IsNullOrEmpty(device.DeviceId)) { @@ -27,13 +27,13 @@ namespace SoilMoistureAPI.Controllers } // Check if device already exists - var existingDevice = await _context.Devices.FindAsync(device.DeviceId); + var existingDevice = await _context.SoilMoisturesFlat.FindAsync(device.DeviceId); if (existingDevice != null) { return Conflict("Device with the same DeviceId already exists."); } - _context.Devices.Add(device); + _context.SoilMoisturesFlat.Add(device); await _context.SaveChangesAsync(); return CreatedAtAction(nameof(GetDevice), new { id = device.DeviceId }, device); @@ -41,10 +41,9 @@ namespace SoilMoistureAPI.Controllers // GET: api/Device/{id} [HttpGet("{id}")] - public async Task> GetDevice(string id) + public async Task> GetDevice(string id) { - var device = await _context.Devices - .Include(d => d.SoilMoistures) + var device = await _context.SoilMoisturesFlat .FirstOrDefaultAsync(d => d.DeviceId == id); if (device == null) @@ -64,7 +63,7 @@ namespace SoilMoistureAPI.Controllers return BadRequest("Nickname cannot be empty."); } - var device = await _context.Devices.FindAsync(id); + var device = await _context.SoilMoisturesFlat.FindAsync(id); if (device == null) { return NotFound("Device not found."); @@ -95,13 +94,13 @@ namespace SoilMoistureAPI.Controllers [HttpDelete("{id}")] public async Task DeleteDevice(string id) { - var device = await _context.Devices.FindAsync(id); + var device = await _context.SoilMoisturesFlat.FindAsync(id); if (device == null) { return NotFound("Device not found."); } - _context.Devices.Remove(device); + _context.SoilMoisturesFlat.Remove(device); await _context.SaveChangesAsync(); return NoContent(); // 204 No Content @@ -109,7 +108,7 @@ namespace SoilMoistureAPI.Controllers private bool DeviceExists(string id) { - return _context.Devices.Any(e => e.DeviceId == id); + return _context.SoilMoisturesFlat.Any(e => e.DeviceId == id); } } } diff --git a/SoilMoistureAPI/Controllers/SoilMoistureController.cs b/SoilMoistureAPI/Controllers/SoilMoistureController.cs index e93da9c..bc138df 100644 --- a/SoilMoistureAPI/Controllers/SoilMoistureController.cs +++ b/SoilMoistureAPI/Controllers/SoilMoistureController.cs @@ -9,9 +9,9 @@ namespace SoilMoistureAPI.Controllers [ApiController] public class SoilMoistureController : ControllerBase { - private readonly SoilMoistureContext _context; + private readonly SoilMoistureFlatContext _context; - public SoilMoistureController(SoilMoistureContext context) + public SoilMoistureController(SoilMoistureFlatContext context) { _context = context; } @@ -25,58 +25,52 @@ namespace SoilMoistureAPI.Controllers return BadRequest("No data received."); } - // Basic validation: ensure required fields are provided. if (string.IsNullOrEmpty(data.DeviceId)) { ModelState.AddModelError("DeviceId", "The DeviceId field is required."); } - // You might also want to validate moisture level here. if (!ModelState.IsValid) { return BadRequest(ModelState); } - // Check if a record for this device already exists - var existingRecord = await _context.SoilMoistures - .Include(sm => sm.Device) + // Attempt to find an existing record for the device + var existingRecord = await _context.SoilMoisturesFlat .FirstOrDefaultAsync(sm => sm.DeviceId == data.DeviceId); if (existingRecord != null) { - // Update the existing record + // Update existing record existingRecord.MoistureLevel = data.MoistureLevel; existingRecord.Timestamp = DateTime.UtcNow; - _context.SoilMoistures.Update(existingRecord); + _context.SoilMoisturesFlat.Update(existingRecord); await _context.SaveChangesAsync(); return Ok(existingRecord); } else { - // Create a new record - var newRecord = new SoilMoisture + // Insert new record + var newRecord = new SoilMoistureFlat { DeviceId = data.DeviceId, MoistureLevel = data.MoistureLevel, Timestamp = DateTime.UtcNow, - Device = new Device - { - DeviceId = data.DeviceId, - Nickname = "Dave" - } + Nickname = "Dave" }; - _context.SoilMoistures.Add(newRecord); + _context.SoilMoisturesFlat.Add(newRecord); await _context.SaveChangesAsync(); return Ok(newRecord); } } + // GET: api/SoilMoisture/5 [HttpGet("{id}")] - public async Task> GetSoilMoisture(int id) + public async Task> GetSoilMoisture(int id) { - var soilMoisture = await _context.SoilMoistures.FindAsync(id); + var soilMoisture = await _context.SoilMoisturesFlat.FindAsync(id); if (soilMoisture == null) { @@ -88,9 +82,9 @@ namespace SoilMoistureAPI.Controllers // GET: api/SoilMoisture [HttpGet] - public async Task>> GetSoilMoistures() + public async Task>> GetSoilMoistures() { - return await _context.SoilMoistures.ToListAsync(); + return await _context.SoilMoisturesFlat.ToListAsync(); } } } \ No newline at end of file diff --git a/SoilMoistureAPI/Data/SoilMoistureContext.cs b/SoilMoistureAPI/Data/SoilMoistureContext.cs deleted file mode 100644 index c3422fd..0000000 --- a/SoilMoistureAPI/Data/SoilMoistureContext.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using SoilMoistureAPI.Models; - -namespace SoilMoistureAPI.Data -{ - public class SoilMoistureContext : DbContext - { - public SoilMoistureContext(DbContextOptions options) : base(options) - { - } - - public DbSet SoilMoistures { get; set; } - public DbSet Devices { get; set; } // New DbSet for Devices - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - // Configure the primary key for Device - modelBuilder.Entity() - .HasKey(d => d.DeviceId); - - // Configure one-to-many relationship - modelBuilder.Entity() - .HasMany(d => d.SoilMoistures) - .WithOne(s => s.Device) - .HasForeignKey(s => s.DeviceId) - .OnDelete(DeleteBehavior.Cascade); - } - } -} diff --git a/SoilMoistureAPI/Data/SoilMoistureFlatContext.cs b/SoilMoistureAPI/Data/SoilMoistureFlatContext.cs new file mode 100644 index 0000000..cd1b2d5 --- /dev/null +++ b/SoilMoistureAPI/Data/SoilMoistureFlatContext.cs @@ -0,0 +1,35 @@ +using Microsoft.EntityFrameworkCore; +using SoilMoistureAPI.Models; + +namespace SoilMoistureAPI.Data +{ + public class SoilMoistureFlatContext : DbContext + { + public DbSet SoilMoisturesFlat { get; set; } + + public SoilMoistureFlatContext(DbContextOptions options) + : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + // Optionally configure the SoilMoistureFlat entity + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id); + entity.Property(e => e.DeviceId) + .IsRequired(); + entity.Property(e => e.MoistureLevel) + .IsRequired(); + entity.Property(e => e.Nickname) + .IsRequired(); + + // Optionally, set default SQL for Timestamp if using SQL Server + // entity.Property(e => e.Timestamp).HasDefaultValueSql("GETUTCDATE()"); + }); + + base.OnModelCreating(modelBuilder); + } + } +} diff --git a/SoilMoistureAPI/Migrations/20250109170429_InitialCreate.cs b/SoilMoistureAPI/Migrations/20250109170429_InitialCreate.cs deleted file mode 100644 index 69f344d..0000000 --- a/SoilMoistureAPI/Migrations/20250109170429_InitialCreate.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace SoilMoistureAPI.Migrations -{ - /// - public partial class InitialCreate : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Devices", - columns: table => new - { - DeviceId = table.Column(type: "TEXT", nullable: false), - Nickname = table.Column(type: "TEXT", maxLength: 100, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Devices", x => x.DeviceId); - }); - - migrationBuilder.CreateTable( - name: "SoilMoistures", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - DeviceId = table.Column(type: "TEXT", nullable: false), - MoistureLevel = table.Column(type: "REAL", nullable: false), - Timestamp = table.Column(type: "TEXT", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_SoilMoistures", x => x.Id); - table.ForeignKey( - name: "FK_SoilMoistures_Devices_DeviceId", - column: x => x.DeviceId, - principalTable: "Devices", - principalColumn: "DeviceId", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_SoilMoistures_DeviceId", - table: "SoilMoistures", - column: "DeviceId"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "SoilMoistures"); - - migrationBuilder.DropTable( - name: "Devices"); - } - } -} diff --git a/SoilMoistureAPI/Migrations/20250109170429_InitialCreate.Designer.cs b/SoilMoistureAPI/Migrations/20250114224916_InitialCreate.Designer.cs similarity index 55% rename from SoilMoistureAPI/Migrations/20250109170429_InitialCreate.Designer.cs rename to SoilMoistureAPI/Migrations/20250114224916_InitialCreate.Designer.cs index bf0617a..b2abc99 100644 --- a/SoilMoistureAPI/Migrations/20250109170429_InitialCreate.Designer.cs +++ b/SoilMoistureAPI/Migrations/20250114224916_InitialCreate.Designer.cs @@ -10,8 +10,8 @@ using SoilMoistureAPI.Data; namespace SoilMoistureAPI.Migrations { - [DbContext(typeof(SoilMoistureContext))] - [Migration("20250109170429_InitialCreate")] + [DbContext(typeof(SoilMoistureFlatContext))] + [Migration("20250114224916_InitialCreate")] partial class InitialCreate { /// @@ -20,22 +20,7 @@ namespace SoilMoistureAPI.Migrations #pragma warning disable 612, 618 modelBuilder.HasAnnotation("ProductVersion", "9.0.0"); - modelBuilder.Entity("SoilMoistureAPI.Models.Device", b => - { - b.Property("DeviceId") - .HasColumnType("TEXT"); - - b.Property("Nickname") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("TEXT"); - - b.HasKey("DeviceId"); - - b.ToTable("Devices"); - }); - - modelBuilder.Entity("SoilMoistureAPI.Models.SoilMoisture", b => + modelBuilder.Entity("SoilMoistureAPI.Models.SoilMoistureFlat", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -48,30 +33,16 @@ namespace SoilMoistureAPI.Migrations b.Property("MoistureLevel") .HasColumnType("REAL"); + b.Property("Nickname") + .IsRequired() + .HasColumnType("TEXT"); + b.Property("Timestamp") .HasColumnType("TEXT"); b.HasKey("Id"); - b.HasIndex("DeviceId"); - - b.ToTable("SoilMoistures"); - }); - - modelBuilder.Entity("SoilMoistureAPI.Models.SoilMoisture", b => - { - b.HasOne("SoilMoistureAPI.Models.Device", "Device") - .WithMany("SoilMoistures") - .HasForeignKey("DeviceId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Device"); - }); - - modelBuilder.Entity("SoilMoistureAPI.Models.Device", b => - { - b.Navigation("SoilMoistures"); + b.ToTable("SoilMoisturesFlat"); }); #pragma warning restore 612, 618 } diff --git a/SoilMoistureAPI/Migrations/20250114224916_InitialCreate.cs b/SoilMoistureAPI/Migrations/20250114224916_InitialCreate.cs new file mode 100644 index 0000000..b4c24e3 --- /dev/null +++ b/SoilMoistureAPI/Migrations/20250114224916_InitialCreate.cs @@ -0,0 +1,38 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace SoilMoistureAPI.Migrations +{ + /// + public partial class InitialCreate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "SoilMoisturesFlat", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + DeviceId = table.Column(type: "TEXT", nullable: false), + MoistureLevel = table.Column(type: "REAL", nullable: false), + Timestamp = table.Column(type: "TEXT", nullable: false), + Nickname = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SoilMoisturesFlat", x => x.Id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "SoilMoisturesFlat"); + } + } +} diff --git a/SoilMoistureAPI/Migrations/SoilMoistureContextModelSnapshot.cs b/SoilMoistureAPI/Migrations/SoilMoistureFlatContextModelSnapshot.cs similarity index 52% rename from SoilMoistureAPI/Migrations/SoilMoistureContextModelSnapshot.cs rename to SoilMoistureAPI/Migrations/SoilMoistureFlatContextModelSnapshot.cs index 2b60a24..d8d9dc6 100644 --- a/SoilMoistureAPI/Migrations/SoilMoistureContextModelSnapshot.cs +++ b/SoilMoistureAPI/Migrations/SoilMoistureFlatContextModelSnapshot.cs @@ -9,30 +9,15 @@ using SoilMoistureAPI.Data; namespace SoilMoistureAPI.Migrations { - [DbContext(typeof(SoilMoistureContext))] - partial class SoilMoistureContextModelSnapshot : ModelSnapshot + [DbContext(typeof(SoilMoistureFlatContext))] + partial class SoilMoistureFlatContextModelSnapshot : ModelSnapshot { protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder.HasAnnotation("ProductVersion", "9.0.0"); - modelBuilder.Entity("SoilMoistureAPI.Models.Device", b => - { - b.Property("DeviceId") - .HasColumnType("TEXT"); - - b.Property("Nickname") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("TEXT"); - - b.HasKey("DeviceId"); - - b.ToTable("Devices"); - }); - - modelBuilder.Entity("SoilMoistureAPI.Models.SoilMoisture", b => + modelBuilder.Entity("SoilMoistureAPI.Models.SoilMoistureFlat", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -45,30 +30,16 @@ namespace SoilMoistureAPI.Migrations b.Property("MoistureLevel") .HasColumnType("REAL"); + b.Property("Nickname") + .IsRequired() + .HasColumnType("TEXT"); + b.Property("Timestamp") .HasColumnType("TEXT"); b.HasKey("Id"); - b.HasIndex("DeviceId"); - - b.ToTable("SoilMoistures"); - }); - - modelBuilder.Entity("SoilMoistureAPI.Models.SoilMoisture", b => - { - b.HasOne("SoilMoistureAPI.Models.Device", "Device") - .WithMany("SoilMoistures") - .HasForeignKey("DeviceId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Device"); - }); - - modelBuilder.Entity("SoilMoistureAPI.Models.Device", b => - { - b.Navigation("SoilMoistures"); + b.ToTable("SoilMoisturesFlat"); }); #pragma warning restore 612, 618 } diff --git a/SoilMoistureAPI/Models/Device.cs b/SoilMoistureAPI/Models/Device.cs index ae7b2ff..9caa4e1 100644 --- a/SoilMoistureAPI/Models/Device.cs +++ b/SoilMoistureAPI/Models/Device.cs @@ -13,6 +13,6 @@ namespace SoilMoistureAPI.Models public string Nickname { get; set; } // Navigation Property - public ICollection SoilMoistures { get; set; } + //public ICollection SoilMoistures { get; set; } } } diff --git a/SoilMoistureAPI/Models/SoilMoistureFlat.cs b/SoilMoistureAPI/Models/SoilMoistureFlat.cs new file mode 100644 index 0000000..84612a7 --- /dev/null +++ b/SoilMoistureAPI/Models/SoilMoistureFlat.cs @@ -0,0 +1,12 @@ +namespace SoilMoistureAPI.Models +{ + public class SoilMoistureFlat + { + public int Id { get; set; } + public string DeviceId { get; set; } // Unique identifier for the sensor device + public float MoistureLevel { get; set; } // Current moisture reading + public DateTime Timestamp { get; set; } = DateTime.UtcNow; + public string Nickname { get; set; } // A friendly name for the device + } + +} diff --git a/SoilMoistureAPI/Program.cs b/SoilMoistureAPI/Program.cs index feac9a0..378a3eb 100644 --- a/SoilMoistureAPI/Program.cs +++ b/SoilMoistureAPI/Program.cs @@ -33,7 +33,7 @@ builder.Services.AddCors(options => }); // Register the DB context with SQLite -builder.Services.AddDbContext(options => +builder.Services.AddDbContext(options => options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection"))); // Add Swagger/OpenAPI support @@ -45,7 +45,7 @@ var app = builder.Build(); // Apply migrations at startup using (var scope = app.Services.CreateScope()) { - var db = scope.ServiceProvider.GetRequiredService(); + var db = scope.ServiceProvider.GetRequiredService(); db.Database.Migrate(); }