update API for more simple approach.

This commit is contained in:
programmingPug
2025-01-14 17:50:34 -05:00
parent 2de48f1fc9
commit f65ead854c
11 changed files with 130 additions and 202 deletions

View File

@@ -10,16 +10,16 @@ namespace SoilMoistureAPI.Controllers
[ApiController] [ApiController]
public class DeviceController : ControllerBase public class DeviceController : ControllerBase
{ {
private readonly SoilMoistureContext _context; private readonly SoilMoistureFlatContext _context;
public DeviceController(SoilMoistureContext context) public DeviceController(SoilMoistureFlatContext context)
{ {
_context = context; _context = context;
} }
// POST: api/Device // POST: api/Device
[HttpPost] [HttpPost]
public async Task<ActionResult<Device>> CreateDevice(Device device) public async Task<ActionResult<Device>> CreateDevice(SoilMoistureFlat device)
{ {
if (device == null || string.IsNullOrEmpty(device.DeviceId)) if (device == null || string.IsNullOrEmpty(device.DeviceId))
{ {
@@ -27,13 +27,13 @@ namespace SoilMoistureAPI.Controllers
} }
// Check if device already exists // Check if device already exists
var existingDevice = await _context.Devices.FindAsync(device.DeviceId); var existingDevice = await _context.SoilMoisturesFlat.FindAsync(device.DeviceId);
if (existingDevice != null) if (existingDevice != null)
{ {
return Conflict("Device with the same DeviceId already exists."); return Conflict("Device with the same DeviceId already exists.");
} }
_context.Devices.Add(device); _context.SoilMoisturesFlat.Add(device);
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
return CreatedAtAction(nameof(GetDevice), new { id = device.DeviceId }, device); return CreatedAtAction(nameof(GetDevice), new { id = device.DeviceId }, device);
@@ -41,10 +41,9 @@ namespace SoilMoistureAPI.Controllers
// GET: api/Device/{id} // GET: api/Device/{id}
[HttpGet("{id}")] [HttpGet("{id}")]
public async Task<ActionResult<Device>> GetDevice(string id) public async Task<ActionResult<SoilMoistureFlat>> GetDevice(string id)
{ {
var device = await _context.Devices var device = await _context.SoilMoisturesFlat
.Include(d => d.SoilMoistures)
.FirstOrDefaultAsync(d => d.DeviceId == id); .FirstOrDefaultAsync(d => d.DeviceId == id);
if (device == null) if (device == null)
@@ -64,7 +63,7 @@ namespace SoilMoistureAPI.Controllers
return BadRequest("Nickname cannot be empty."); return BadRequest("Nickname cannot be empty.");
} }
var device = await _context.Devices.FindAsync(id); var device = await _context.SoilMoisturesFlat.FindAsync(id);
if (device == null) if (device == null)
{ {
return NotFound("Device not found."); return NotFound("Device not found.");
@@ -95,13 +94,13 @@ namespace SoilMoistureAPI.Controllers
[HttpDelete("{id}")] [HttpDelete("{id}")]
public async Task<IActionResult> DeleteDevice(string id) public async Task<IActionResult> DeleteDevice(string id)
{ {
var device = await _context.Devices.FindAsync(id); var device = await _context.SoilMoisturesFlat.FindAsync(id);
if (device == null) if (device == null)
{ {
return NotFound("Device not found."); return NotFound("Device not found.");
} }
_context.Devices.Remove(device); _context.SoilMoisturesFlat.Remove(device);
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
return NoContent(); // 204 No Content return NoContent(); // 204 No Content
@@ -109,7 +108,7 @@ namespace SoilMoistureAPI.Controllers
private bool DeviceExists(string id) private bool DeviceExists(string id)
{ {
return _context.Devices.Any(e => e.DeviceId == id); return _context.SoilMoisturesFlat.Any(e => e.DeviceId == id);
} }
} }
} }

View File

@@ -9,9 +9,9 @@ namespace SoilMoistureAPI.Controllers
[ApiController] [ApiController]
public class SoilMoistureController : ControllerBase public class SoilMoistureController : ControllerBase
{ {
private readonly SoilMoistureContext _context; private readonly SoilMoistureFlatContext _context;
public SoilMoistureController(SoilMoistureContext context) public SoilMoistureController(SoilMoistureFlatContext context)
{ {
_context = context; _context = context;
} }
@@ -25,58 +25,52 @@ namespace SoilMoistureAPI.Controllers
return BadRequest("No data received."); return BadRequest("No data received.");
} }
// Basic validation: ensure required fields are provided.
if (string.IsNullOrEmpty(data.DeviceId)) if (string.IsNullOrEmpty(data.DeviceId))
{ {
ModelState.AddModelError("DeviceId", "The DeviceId field is required."); ModelState.AddModelError("DeviceId", "The DeviceId field is required.");
} }
// You might also want to validate moisture level here.
if (!ModelState.IsValid) if (!ModelState.IsValid)
{ {
return BadRequest(ModelState); return BadRequest(ModelState);
} }
// Check if a record for this device already exists // Attempt to find an existing record for the device
var existingRecord = await _context.SoilMoistures var existingRecord = await _context.SoilMoisturesFlat
.Include(sm => sm.Device)
.FirstOrDefaultAsync(sm => sm.DeviceId == data.DeviceId); .FirstOrDefaultAsync(sm => sm.DeviceId == data.DeviceId);
if (existingRecord != null) if (existingRecord != null)
{ {
// Update the existing record // Update existing record
existingRecord.MoistureLevel = data.MoistureLevel; existingRecord.MoistureLevel = data.MoistureLevel;
existingRecord.Timestamp = DateTime.UtcNow; existingRecord.Timestamp = DateTime.UtcNow;
_context.SoilMoistures.Update(existingRecord); _context.SoilMoisturesFlat.Update(existingRecord);
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
return Ok(existingRecord); return Ok(existingRecord);
} }
else else
{ {
// Create a new record // Insert new record
var newRecord = new SoilMoisture var newRecord = new SoilMoistureFlat
{ {
DeviceId = data.DeviceId, DeviceId = data.DeviceId,
MoistureLevel = data.MoistureLevel, MoistureLevel = data.MoistureLevel,
Timestamp = DateTime.UtcNow, Timestamp = DateTime.UtcNow,
Device = new Device Nickname = "Dave"
{
DeviceId = data.DeviceId,
Nickname = "Dave"
}
}; };
_context.SoilMoistures.Add(newRecord); _context.SoilMoisturesFlat.Add(newRecord);
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
return Ok(newRecord); return Ok(newRecord);
} }
} }
// GET: api/SoilMoisture/5 // GET: api/SoilMoisture/5
[HttpGet("{id}")] [HttpGet("{id}")]
public async Task<ActionResult<SoilMoisture>> GetSoilMoisture(int id) public async Task<ActionResult<SoilMoistureFlat>> GetSoilMoisture(int id)
{ {
var soilMoisture = await _context.SoilMoistures.FindAsync(id); var soilMoisture = await _context.SoilMoisturesFlat.FindAsync(id);
if (soilMoisture == null) if (soilMoisture == null)
{ {
@@ -88,9 +82,9 @@ namespace SoilMoistureAPI.Controllers
// GET: api/SoilMoisture // GET: api/SoilMoisture
[HttpGet] [HttpGet]
public async Task<ActionResult<IEnumerable<SoilMoisture>>> GetSoilMoistures() public async Task<ActionResult<IEnumerable<SoilMoistureFlat>>> GetSoilMoistures()
{ {
return await _context.SoilMoistures.ToListAsync(); return await _context.SoilMoisturesFlat.ToListAsync();
} }
} }
} }

View File

@@ -1,29 +0,0 @@
using Microsoft.EntityFrameworkCore;
using SoilMoistureAPI.Models;
namespace SoilMoistureAPI.Data
{
public class SoilMoistureContext : DbContext
{
public SoilMoistureContext(DbContextOptions<SoilMoistureContext> options) : base(options)
{
}
public DbSet<SoilMoisture> SoilMoistures { get; set; }
public DbSet<Device> Devices { get; set; } // New DbSet for Devices
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Configure the primary key for Device
modelBuilder.Entity<Device>()
.HasKey(d => d.DeviceId);
// Configure one-to-many relationship
modelBuilder.Entity<Device>()
.HasMany(d => d.SoilMoistures)
.WithOne(s => s.Device)
.HasForeignKey(s => s.DeviceId)
.OnDelete(DeleteBehavior.Cascade);
}
}
}

View File

@@ -0,0 +1,35 @@
using Microsoft.EntityFrameworkCore;
using SoilMoistureAPI.Models;
namespace SoilMoistureAPI.Data
{
public class SoilMoistureFlatContext : DbContext
{
public DbSet<SoilMoistureFlat> SoilMoisturesFlat { get; set; }
public SoilMoistureFlatContext(DbContextOptions<SoilMoistureFlatContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Optionally configure the SoilMoistureFlat entity
modelBuilder.Entity<SoilMoistureFlat>(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);
}
}
}

View File

@@ -1,63 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace SoilMoistureAPI.Migrations
{
/// <inheritdoc />
public partial class InitialCreate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Devices",
columns: table => new
{
DeviceId = table.Column<string>(type: "TEXT", nullable: false),
Nickname = table.Column<string>(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<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
DeviceId = table.Column<string>(type: "TEXT", nullable: false),
MoistureLevel = table.Column<float>(type: "REAL", nullable: false),
Timestamp = table.Column<DateTime>(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");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "SoilMoistures");
migrationBuilder.DropTable(
name: "Devices");
}
}
}

View File

@@ -10,8 +10,8 @@ using SoilMoistureAPI.Data;
namespace SoilMoistureAPI.Migrations namespace SoilMoistureAPI.Migrations
{ {
[DbContext(typeof(SoilMoistureContext))] [DbContext(typeof(SoilMoistureFlatContext))]
[Migration("20250109170429_InitialCreate")] [Migration("20250114224916_InitialCreate")]
partial class InitialCreate partial class InitialCreate
{ {
/// <inheritdoc /> /// <inheritdoc />
@@ -20,22 +20,7 @@ namespace SoilMoistureAPI.Migrations
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "9.0.0"); modelBuilder.HasAnnotation("ProductVersion", "9.0.0");
modelBuilder.Entity("SoilMoistureAPI.Models.Device", b => modelBuilder.Entity("SoilMoistureAPI.Models.SoilMoistureFlat", b =>
{
b.Property<string>("DeviceId")
.HasColumnType("TEXT");
b.Property<string>("Nickname")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("TEXT");
b.HasKey("DeviceId");
b.ToTable("Devices");
});
modelBuilder.Entity("SoilMoistureAPI.Models.SoilMoisture", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
@@ -48,30 +33,16 @@ namespace SoilMoistureAPI.Migrations
b.Property<float>("MoistureLevel") b.Property<float>("MoistureLevel")
.HasColumnType("REAL"); .HasColumnType("REAL");
b.Property<string>("Nickname")
.IsRequired()
.HasColumnType("TEXT");
b.Property<DateTime>("Timestamp") b.Property<DateTime>("Timestamp")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("DeviceId"); b.ToTable("SoilMoisturesFlat");
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");
}); });
#pragma warning restore 612, 618 #pragma warning restore 612, 618
} }

View File

@@ -0,0 +1,38 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace SoilMoistureAPI.Migrations
{
/// <inheritdoc />
public partial class InitialCreate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "SoilMoisturesFlat",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
DeviceId = table.Column<string>(type: "TEXT", nullable: false),
MoistureLevel = table.Column<float>(type: "REAL", nullable: false),
Timestamp = table.Column<DateTime>(type: "TEXT", nullable: false),
Nickname = table.Column<string>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_SoilMoisturesFlat", x => x.Id);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "SoilMoisturesFlat");
}
}
}

View File

@@ -9,30 +9,15 @@ using SoilMoistureAPI.Data;
namespace SoilMoistureAPI.Migrations namespace SoilMoistureAPI.Migrations
{ {
[DbContext(typeof(SoilMoistureContext))] [DbContext(typeof(SoilMoistureFlatContext))]
partial class SoilMoistureContextModelSnapshot : ModelSnapshot partial class SoilMoistureFlatContextModelSnapshot : ModelSnapshot
{ {
protected override void BuildModel(ModelBuilder modelBuilder) protected override void BuildModel(ModelBuilder modelBuilder)
{ {
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "9.0.0"); modelBuilder.HasAnnotation("ProductVersion", "9.0.0");
modelBuilder.Entity("SoilMoistureAPI.Models.Device", b => modelBuilder.Entity("SoilMoistureAPI.Models.SoilMoistureFlat", b =>
{
b.Property<string>("DeviceId")
.HasColumnType("TEXT");
b.Property<string>("Nickname")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("TEXT");
b.HasKey("DeviceId");
b.ToTable("Devices");
});
modelBuilder.Entity("SoilMoistureAPI.Models.SoilMoisture", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
@@ -45,30 +30,16 @@ namespace SoilMoistureAPI.Migrations
b.Property<float>("MoistureLevel") b.Property<float>("MoistureLevel")
.HasColumnType("REAL"); .HasColumnType("REAL");
b.Property<string>("Nickname")
.IsRequired()
.HasColumnType("TEXT");
b.Property<DateTime>("Timestamp") b.Property<DateTime>("Timestamp")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("DeviceId"); b.ToTable("SoilMoisturesFlat");
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");
}); });
#pragma warning restore 612, 618 #pragma warning restore 612, 618
} }

View File

@@ -13,6 +13,6 @@ namespace SoilMoistureAPI.Models
public string Nickname { get; set; } public string Nickname { get; set; }
// Navigation Property // Navigation Property
public ICollection<SoilMoisture> SoilMoistures { get; set; } //public ICollection<SoilMoisture> SoilMoistures { get; set; }
} }
} }

View File

@@ -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
}
}

View File

@@ -33,7 +33,7 @@ builder.Services.AddCors(options =>
}); });
// Register the DB context with SQLite // Register the DB context with SQLite
builder.Services.AddDbContext<SoilMoistureContext>(options => builder.Services.AddDbContext<SoilMoistureFlatContext>(options =>
options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection"))); options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection")));
// Add Swagger/OpenAPI support // Add Swagger/OpenAPI support
@@ -45,7 +45,7 @@ var app = builder.Build();
// Apply migrations at startup // Apply migrations at startup
using (var scope = app.Services.CreateScope()) using (var scope = app.Services.CreateScope())
{ {
var db = scope.ServiceProvider.GetRequiredService<SoilMoistureContext>(); var db = scope.ServiceProvider.GetRequiredService<SoilMoistureFlatContext>();
db.Database.Migrate(); db.Database.Migrate();
} }