Add time record API endpoint and supporting infrastructure

Introduced a new TimeController with a POST endpoint to insert and retrieve the latest time record. Added ITimeRepository, TimeRepository, and TimeRecord entity. Implemented MediatR command and handler for time insertion. Updated ApplicationDbContext and DI configuration to support the new feature.
This commit is contained in:
OlgunR
2026-03-30 15:16:03 +02:00
parent 36ade1b26b
commit f5224e20f2
8 changed files with 110 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
using DbFirst.Application.Time.Commands;
using DbFirst.Domain.Entities;
using MediatR;
using Microsoft.AspNetCore.Mvc;
namespace DbFirst.API.Controllers;
[ApiController]
[Route("api/[controller]")]
public class TimeController : ControllerBase
{
private readonly IMediator _mediator;
public TimeController(IMediator mediator)
{
_mediator = mediator;
}
[HttpPost]
public async Task<ActionResult<TimeRecord>> InsertAndGetLast(CancellationToken cancellationToken)
{
var result = await _mediator.Send(new InsertTimeCommand(), cancellationToken);
if (result == null)
return NotFound();
return Ok(result);
}
}

View File

@@ -54,6 +54,7 @@ builder.Services.AddApplication();
builder.Services.AddScoped<ICatalogRepository, CatalogRepository>();
builder.Services.AddScoped<IMassDataRepository, MassDataRepository>();
builder.Services.AddScoped<ILayoutRepository, LayoutRepository>();
builder.Services.AddScoped<ITimeRepository, TimeRepository>();
builder.Services.AddDevExpressControls();
builder.Services.AddSignalR();

View File

@@ -0,0 +1,9 @@
using DbFirst.Domain.Entities;
namespace DbFirst.Application.Repositories;
public interface ITimeRepository
{
Task InsertAsync(CancellationToken cancellationToken = default);
Task<TimeRecord?> GetLastAsync(CancellationToken cancellationToken = default);
}

View File

@@ -0,0 +1,6 @@
using DbFirst.Domain.Entities;
using MediatR;
namespace DbFirst.Application.Time.Commands;
public record InsertTimeCommand : IRequest<TimeRecord?>;

View File

@@ -0,0 +1,21 @@
using DbFirst.Application.Repositories;
using DbFirst.Domain.Entities;
using MediatR;
namespace DbFirst.Application.Time.Commands;
public class InsertTimeHandler : IRequestHandler<InsertTimeCommand, TimeRecord?>
{
private readonly ITimeRepository _repository;
public InsertTimeHandler(ITimeRepository repository)
{
_repository = repository;
}
public async Task<TimeRecord?> Handle(InsertTimeCommand request, CancellationToken cancellationToken)
{
await _repository.InsertAsync(cancellationToken);
return await _repository.GetLastAsync(cancellationToken);
}
}

View File

@@ -0,0 +1,6 @@
namespace DbFirst.Domain.Entities;
public class TimeRecord
{
public DateTime? Now { get; set; }
}

View File

@@ -16,6 +16,7 @@ public partial class ApplicationDbContext : DbContext
public virtual DbSet<VwmyCatalog> VwmyCatalogs { get; set; }
public virtual DbSet<SmfLayout> SmfLayouts { get; set; }
public virtual DbSet<TimeRecord> Times { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
@@ -83,6 +84,16 @@ public partial class ApplicationDbContext : DbContext
.HasColumnName("CHANGED_WHEN");
});
modelBuilder.Entity<TimeRecord>(entity =>
{
entity.HasNoKey();
entity.ToTable("TIME");
entity.Property(e => e.Now)
.HasColumnType("datetime")
.HasColumnName("NOW");
});
OnModelCreatingPartial(modelBuilder);
}

View File

@@ -0,0 +1,28 @@
using DbFirst.Application.Repositories;
using DbFirst.Domain.Entities;
using Microsoft.EntityFrameworkCore;
namespace DbFirst.Infrastructure.Repositories;
public class TimeRepository : ITimeRepository
{
private readonly ApplicationDbContext _db;
public TimeRepository(ApplicationDbContext db)
{
_db = db;
}
public async Task InsertAsync(CancellationToken cancellationToken = default)
{
await _db.Database.ExecuteSqlRawAsync("INSERT INTO [TIME] (NOW) VALUES (GETDATE())", cancellationToken);
}
public async Task<TimeRecord?> GetLastAsync(CancellationToken cancellationToken = default)
{
return await _db.Times
.AsNoTracking()
.OrderByDescending(t => t.Now)
.FirstOrDefaultAsync(cancellationToken);
}
}