ChangeLogRepository (окончание)
This commit is contained in:
parent
a3d90e05f7
commit
198a65b1d2
@ -1,6 +1,7 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Persistence.Models;
|
using Persistence.Models;
|
||||||
|
using Persistence.Models.Requests;
|
||||||
using Persistence.Repositories;
|
using Persistence.Repositories;
|
||||||
|
|
||||||
namespace Persistence.API.Controllers;
|
namespace Persistence.API.Controllers;
|
||||||
@ -58,37 +59,17 @@ public class ChangeLogController : ControllerBase, IChangeLogApi
|
|||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpPost("replace")]
|
||||||
public async Task<ActionResult<IEnumerable<DataWithWellDepthAndSectionDto>>> GetCurrent(
|
public async Task<IActionResult> ClearAndInsertRange(
|
||||||
Guid idDiscriminator,
|
Guid idDiscriminator,
|
||||||
|
IEnumerable<DataWithWellDepthAndSectionDto> dtos,
|
||||||
CancellationToken token)
|
CancellationToken token)
|
||||||
{
|
{
|
||||||
var date = new DateTimeOffset(3000, 1, 1, 0, 0, 0, TimeSpan.Zero);
|
var userId = User.GetUserId<Guid>();
|
||||||
var result = await repository.GetByDate(idDiscriminator, date, token);
|
var result = await repository.ClearAndInsertRange(userId, idDiscriminator, dtos, token);
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("moment")]
|
|
||||||
public async Task<ActionResult<IEnumerable<DataWithWellDepthAndSectionDto>>> GetByDate(
|
|
||||||
Guid idDiscriminator,
|
|
||||||
DateTimeOffset moment,
|
|
||||||
CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await repository.GetByDate(idDiscriminator, moment, token);
|
|
||||||
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("history")]
|
|
||||||
public async Task<ActionResult<IEnumerable<ChangeLogDto>>> GetChangeLogForDate(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await repository.GetChangeLogForDate(idDiscriminator, dateBegin, dateEnd, token);
|
|
||||||
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[HttpPut]
|
[HttpPut]
|
||||||
public async Task<ActionResult<int>> Update(
|
public async Task<ActionResult<int>> Update(
|
||||||
Guid idDiscriminator,
|
Guid idDiscriminator,
|
||||||
@ -113,5 +94,48 @@ public class ChangeLogController : ControllerBase, IChangeLogApi
|
|||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<ActionResult<PaginationContainer<DataWithWellDepthAndSectionDto>>> GetCurrent(
|
||||||
|
Guid idDiscriminator,
|
||||||
|
[FromQuery]SectionPartRequest request,
|
||||||
|
CancellationToken token)
|
||||||
|
{
|
||||||
|
var moment = new DateTimeOffset(3000, 1, 1, 0, 0, 0, TimeSpan.Zero);
|
||||||
|
var result = await repository.GetByDate(idDiscriminator, moment, request, token);
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("moment")]
|
||||||
|
public async Task<ActionResult<PaginationContainer<DataWithWellDepthAndSectionDto>>> GetByDate(
|
||||||
|
Guid idDiscriminator,
|
||||||
|
DateTimeOffset moment,
|
||||||
|
SectionPartRequest request,
|
||||||
|
CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await repository.GetByDate(idDiscriminator, moment, request, token);
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("history")]
|
||||||
|
public async Task<ActionResult<IEnumerable<ChangeLogDto>>> GetChangeLogForDate(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await repository.GetChangeLogForDate(idDiscriminator, dateBegin, dateEnd, token);
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("datesChange")]
|
||||||
|
public async Task<ActionResult<IEnumerable<DateOnly>>> GetDatesChange(Guid idDiscriminator, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await repository.GetDatesChange(idDiscriminator, token);
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using Mapster;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Persistence.Database.Model;
|
using Persistence.Database.Model;
|
||||||
using Persistence.Models;
|
using Persistence.Models;
|
||||||
@ -10,6 +11,17 @@ public static class DependencyInjection
|
|||||||
{
|
{
|
||||||
public static void MapsterSetup()
|
public static void MapsterSetup()
|
||||||
{
|
{
|
||||||
|
TypeAdapterConfig.GlobalSettings.Default.Config
|
||||||
|
.ForType<ChangeLog, ChangeLogDto>()
|
||||||
|
.Map(dest => dest.Value, src => new DataWithWellDepthAndSectionDto()
|
||||||
|
{
|
||||||
|
DepthEnd = src.DepthEnd,
|
||||||
|
DepthStart = src.DepthStart,
|
||||||
|
IdSection = src.IdSection,
|
||||||
|
Value = src.Value,
|
||||||
|
Id = src.Id
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IServiceCollection AddInfrastructure(this IServiceCollection services)
|
public static IServiceCollection AddInfrastructure(this IServiceCollection services)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Persistence.Database.Model;
|
using Persistence.Database.Model;
|
||||||
using Persistence.Models;
|
using Persistence.Models;
|
||||||
|
using Persistence.Models.Requests;
|
||||||
using Persistence.Repositories;
|
using Persistence.Repositories;
|
||||||
|
|
||||||
namespace Persistence.Repository.Repositories;
|
namespace Persistence.Repository.Repositories;
|
||||||
@ -14,18 +15,46 @@ public class ChangeLogRepository : IChangeLogRepository
|
|||||||
this.db = db;
|
this.db = db;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> Clear(Guid idUser, Guid idDiscriminator, CancellationToken token)
|
public Task<int> InsertRange(Guid idUser, Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token)
|
||||||
|
{
|
||||||
|
foreach (var dto in dtos)
|
||||||
|
{
|
||||||
|
var entity = CreateEntityFromDto(idUser, idDiscriminator, dto);
|
||||||
|
db.Set<ChangeLog>().Add(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = db.SaveChangesAsync(token);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> MarkAsDeleted(Guid idUser, IEnumerable<Guid> ids, CancellationToken token)
|
||||||
|
{
|
||||||
|
var query = db.Set<ChangeLog>().Where(s => ids.Contains(s.Id));
|
||||||
|
var entities = await query.ToArrayAsync(token);
|
||||||
|
|
||||||
|
var result = await Clear(idUser, entities, token);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> MarkAsDeleted(Guid idUser, Guid idDiscriminator, CancellationToken token)
|
||||||
|
{
|
||||||
|
var query = db.Set<ChangeLog>()
|
||||||
|
.Where(s => s.IdDiscriminator == idDiscriminator)
|
||||||
|
.Where(e => e.Obsolete == null);
|
||||||
|
var entities = await query.ToArrayAsync(token);
|
||||||
|
|
||||||
|
var result = await Clear(idUser, entities, token);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<int> Clear(Guid idUser, IEnumerable<ChangeLog> entities, CancellationToken token)
|
||||||
{
|
{
|
||||||
var updateTime = DateTimeOffset.UtcNow;
|
var updateTime = DateTimeOffset.UtcNow;
|
||||||
|
|
||||||
var dbSet = db.Set<ChangeLog>();
|
foreach (var entity in entities)
|
||||||
var query = dbSet
|
|
||||||
.Where(s => s.IdDiscriminator == idDiscriminator)
|
|
||||||
.Where(e => e.Obsolete == null);
|
|
||||||
|
|
||||||
var entitiesToDelete = await query.ToArrayAsync(token);
|
|
||||||
|
|
||||||
foreach (var entity in entitiesToDelete)
|
|
||||||
{
|
{
|
||||||
entity.Obsolete = updateTime;
|
entity.Obsolete = updateTime;
|
||||||
entity.IdEditor = idUser;
|
entity.IdEditor = idUser;
|
||||||
@ -40,7 +69,7 @@ public class ChangeLogRepository : IChangeLogRepository
|
|||||||
using var transaction = await db.Database.BeginTransactionAsync(token);
|
using var transaction = await db.Database.BeginTransactionAsync(token);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result += await Clear(idUser, idDiscriminator, token);
|
result += await MarkAsDeleted(idUser, idDiscriminator, token);
|
||||||
result += await InsertRange(idUser, idDiscriminator, dtos, token);
|
result += await InsertRange(idUser, idDiscriminator, dtos, token);
|
||||||
|
|
||||||
await transaction.CommitAsync(token);
|
await transaction.CommitAsync(token);
|
||||||
@ -53,57 +82,154 @@ public class ChangeLogRepository : IChangeLogRepository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<ChangeLogDto>> GetChangeLogForDate(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token)
|
public async Task<int> UpdateRange(Guid idUser, Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token)
|
||||||
{
|
{
|
||||||
var dbSet = db.Set<ChangeLog>();
|
var dbSet = db.Set<ChangeLog>();
|
||||||
var query = dbSet.Where(s => s.IdDiscriminator == idDiscriminator);
|
|
||||||
|
|
||||||
var min = dateBegin;
|
var updatedIds = dtos.Select(d => d.Id);
|
||||||
var max = dateEnd;
|
var updatedEntities = dbSet
|
||||||
|
.Where(s => updatedIds.Contains(s.Id))
|
||||||
|
.ToDictionary(s => s.Id);
|
||||||
|
|
||||||
|
var result = 0;
|
||||||
|
using var transaction = await db.Database.BeginTransactionAsync(token);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (var dto in dtos)
|
||||||
|
{
|
||||||
|
var newEntity = CreateEntityFromDto(idUser, idDiscriminator, dto);
|
||||||
|
dbSet.Add(newEntity);
|
||||||
|
|
||||||
|
var updatedEntity = updatedEntities.GetValueOrDefault(dto.Id)!;
|
||||||
|
updatedEntity.IdNext = newEntity.Id;
|
||||||
|
updatedEntity.Obsolete = DateTimeOffset.UtcNow;
|
||||||
|
updatedEntity.IdEditor = idUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.SaveChangesAsync(token);
|
||||||
|
await transaction.CommitAsync(token);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
await transaction.RollbackAsync(token);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PaginationContainer<DataWithWellDepthAndSectionDto>> GetByDate(
|
||||||
|
Guid idDiscriminator,
|
||||||
|
DateTimeOffset momentUtc,
|
||||||
|
SectionPartRequest request,
|
||||||
|
CancellationToken token)
|
||||||
|
{
|
||||||
|
var query = BuildQuery(idDiscriminator, momentUtc, request);
|
||||||
|
var result = await BuildPaginationContainer(query, request, token);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IQueryable<ChangeLog> BuildQuery(Guid idDiscriminator, DateTimeOffset momentUtc, SectionPartRequest request)
|
||||||
|
{
|
||||||
|
var query = db.Set<ChangeLog>()
|
||||||
|
.Where(e => e.IdDiscriminator == idDiscriminator)
|
||||||
|
.Where(e => e.Creation <= momentUtc)
|
||||||
|
.Where(e => e.Obsolete == null || e.Obsolete >= momentUtc);
|
||||||
|
|
||||||
|
if (request.IdSection.HasValue)
|
||||||
|
{
|
||||||
|
query = query.Where(e => e.IdSection == request.IdSection);
|
||||||
|
}
|
||||||
|
if (request.DepthStart.HasValue)
|
||||||
|
{
|
||||||
|
query = query.Where(e => e.DepthStart >= request.DepthStart);
|
||||||
|
}
|
||||||
|
if (request.DepthEnd.HasValue)
|
||||||
|
{
|
||||||
|
query = query.Where(e => e.DepthEnd <= request.DepthEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<ChangeLogDto>> GetChangeLogForDate(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token)
|
||||||
|
{
|
||||||
|
var query = db.Set<ChangeLog>().Where(s => s.IdDiscriminator == idDiscriminator);
|
||||||
|
|
||||||
|
var min = new DateTimeOffset(dateBegin.Year, dateBegin.Month, dateBegin.Day, 0, 0, 0, TimeSpan.Zero);
|
||||||
|
var max = new DateTimeOffset(dateEnd.Year, dateEnd.Month, dateEnd.Day, 0, 0, 0, TimeSpan.Zero);
|
||||||
|
|
||||||
var createdQuery = query.Where(e => e.Creation >= min && e.Creation <= max);
|
var createdQuery = query.Where(e => e.Creation >= min && e.Creation <= max);
|
||||||
var editedQuery = query.Where(e => e.Obsolete != null && e.Obsolete >= min && e.Obsolete <= max);
|
var editedQuery = query.Where(e => e.Obsolete != null && e.Obsolete >= min && e.Obsolete <= max);
|
||||||
|
|
||||||
query = createdQuery.Union(editedQuery);
|
query = createdQuery.Union(editedQuery);
|
||||||
var entities = await query.ToListAsync(token);
|
var entities = await query.ToArrayAsync(token);
|
||||||
|
|
||||||
var dtos = entities.Select(e => new ChangeLogDto
|
var dtos = entities.Select(e => e.Adapt<ChangeLogDto>());
|
||||||
{
|
|
||||||
Creation = e.Creation,
|
|
||||||
IdAuthor = e.IdAuthor,
|
|
||||||
IdEditor = e.IdEditor,
|
|
||||||
IdNext = e.IdNext,
|
|
||||||
Obsolete = e.Obsolete,
|
|
||||||
Value = new DataWithWellDepthAndSectionDto()
|
|
||||||
{
|
|
||||||
Value = e.Value,
|
|
||||||
IdSection = e.IdSection,
|
|
||||||
Id = e.Id,
|
|
||||||
DepthEnd = e.DepthEnd,
|
|
||||||
DepthStart = e.DepthStart
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return dtos;
|
return dtos;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<DataWithWellDepthAndSectionDto>> GetByDate(Guid idDiscriminator, DateTimeOffset momentUtc, CancellationToken token)
|
|
||||||
{
|
|
||||||
var dbSet = db.Set<ChangeLog>();
|
|
||||||
var dbQuery = dbSet
|
|
||||||
.Where(s => s.IdDiscriminator == idDiscriminator)
|
|
||||||
.Where(e => e.Creation <= momentUtc)
|
|
||||||
.Where(e => e.Obsolete == null || e.Obsolete >= momentUtc);
|
|
||||||
|
|
||||||
var entities = await dbQuery.ToArrayAsync(token);
|
|
||||||
|
private async Task<PaginationContainer<DataWithWellDepthAndSectionDto>> BuildPaginationContainer(IQueryable<ChangeLog> query, SectionPartRequest request, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = new PaginationContainer<DataWithWellDepthAndSectionDto>
|
||||||
|
{
|
||||||
|
Skip = request.Skip ?? 0,
|
||||||
|
Take = request.Take ?? 32,
|
||||||
|
Items = Enumerable.Empty<DataWithWellDepthAndSectionDto>(),
|
||||||
|
Count = await query.CountAsync(token)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!String.IsNullOrEmpty(request.SortSettings))
|
||||||
|
{
|
||||||
|
query = query.SortBy(request.SortSettings);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
query = query
|
||||||
|
.OrderBy(e => e.IdSection)
|
||||||
|
.ThenBy(e => e.DepthStart)
|
||||||
|
.ThenBy(e => e.DepthEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
var entities = await query
|
||||||
|
.Skip(result.Skip)
|
||||||
|
.Take(result.Take)
|
||||||
|
.ToArrayAsync(token);
|
||||||
|
|
||||||
var dtos = entities.Select(e => e.Adapt<DataWithWellDepthAndSectionDto>());
|
var dtos = entities.Select(e => e.Adapt<DataWithWellDepthAndSectionDto>());
|
||||||
|
result.Items = dtos;
|
||||||
|
|
||||||
return dtos;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<IEnumerable<DateOnly>> GetDatesChange(CancellationToken token)
|
public async Task<IEnumerable<DateOnly>> GetDatesChange(Guid idDiscriminator, CancellationToken token)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
var query = db.Set<ChangeLog>().Where(e => e.IdDiscriminator == idDiscriminator);
|
||||||
|
|
||||||
|
var datesCreateQuery = query
|
||||||
|
.Select(e => e.Creation)
|
||||||
|
.Distinct();
|
||||||
|
|
||||||
|
var datesCreate = await datesCreateQuery.ToArrayAsync(token);
|
||||||
|
|
||||||
|
var datesUpdateQuery = query
|
||||||
|
.Where(e => e.Obsolete != null)
|
||||||
|
.Select(e => e.Obsolete!.Value)
|
||||||
|
.Distinct();
|
||||||
|
|
||||||
|
var datesUpdate = await datesUpdateQuery.ToArrayAsync(token);
|
||||||
|
|
||||||
|
var dates = Enumerable.Concat(datesCreate, datesUpdate);
|
||||||
|
var datesOnly = dates
|
||||||
|
.Select(d => new DateOnly(d.Year, d.Month, d.Day))
|
||||||
|
.Distinct()
|
||||||
|
.OrderBy(d => d);
|
||||||
|
|
||||||
|
return datesOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<IEnumerable<IDictionary<string, object>>> GetGtDate(DateTimeOffset dateBegin, CancellationToken token)
|
public Task<IEnumerable<IDictionary<string, object>>> GetGtDate(DateTimeOffset dateBegin, CancellationToken token)
|
||||||
@ -111,19 +237,6 @@ public class ChangeLogRepository : IChangeLogRepository
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<int> InsertRange(Guid idUser, Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token)
|
|
||||||
{
|
|
||||||
foreach (var dto in dtos)
|
|
||||||
{
|
|
||||||
var entity = CreateEntityFromDto(idUser, idDiscriminator, dto);
|
|
||||||
db.Set<ChangeLog>().Add(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = db.SaveChangesAsync(token);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ChangeLog CreateEntityFromDto(Guid idUser, Guid idDiscriminator, DataWithWellDepthAndSectionDto dto)
|
private ChangeLog CreateEntityFromDto(Guid idUser, Guid idDiscriminator, DataWithWellDepthAndSectionDto dto)
|
||||||
{
|
{
|
||||||
var entity = new ChangeLog()
|
var entity = new ChangeLog()
|
||||||
@ -143,52 +256,4 @@ public class ChangeLogRepository : IChangeLogRepository
|
|||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> MarkAsDeleted(Guid idUser, IEnumerable<Guid> ids, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = 0;
|
|
||||||
var dbSet = db.Set<ChangeLog>();
|
|
||||||
|
|
||||||
var updatedEntity = dbSet
|
|
||||||
.Where(s => ids.Contains(s.Id))
|
|
||||||
.FirstOrDefault();
|
|
||||||
if (updatedEntity != null)
|
|
||||||
{
|
|
||||||
updatedEntity.Obsolete = DateTimeOffset.UtcNow;
|
|
||||||
|
|
||||||
result = await db.SaveChangesAsync(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<int> UpdateOrInsertRange(int idUser, IEnumerable<IDictionary<string, object>> dtos, CancellationToken token)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> UpdateRange(Guid idUser, Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token)
|
|
||||||
{
|
|
||||||
var dbSet = db.Set<ChangeLog>();
|
|
||||||
|
|
||||||
var updatedIds = dtos.Select(d => d.Id);
|
|
||||||
var updatedEntities = dbSet
|
|
||||||
.Where(s => updatedIds.Contains(s.Id))
|
|
||||||
.ToDictionary(s => s.Id);
|
|
||||||
//todo
|
|
||||||
foreach (var dto in dtos)
|
|
||||||
{
|
|
||||||
var newEntity = CreateEntityFromDto(idUser, idDiscriminator, dto);
|
|
||||||
dbSet.Add(newEntity);
|
|
||||||
|
|
||||||
var updatedEntity = updatedEntities.GetValueOrDefault(dto.Id)!;
|
|
||||||
updatedEntity.IdNext = newEntity.Id;
|
|
||||||
updatedEntity.Obsolete = DateTimeOffset.UtcNow;
|
|
||||||
updatedEntity.IdEditor = idUser;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = await db.SaveChangesAsync(token);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Persistence.Models;
|
using Persistence.Models;
|
||||||
|
using Persistence.Models.Requests;
|
||||||
|
|
||||||
namespace Persistence.API;
|
namespace Persistence.API;
|
||||||
|
|
||||||
@ -9,21 +10,32 @@ namespace Persistence.API;
|
|||||||
public interface IChangeLogApi
|
public interface IChangeLogApi
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получение данных на текущую дату
|
/// Импорт с заменой: удаление старых строк и добавление новых
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="idDiscriminator"></param>
|
/// <param name="idDiscriminator"></param>
|
||||||
|
/// <param name="dtos"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<ActionResult<IEnumerable<DataWithWellDepthAndSectionDto>>> GetCurrent(Guid idDiscriminator, CancellationToken token);
|
Task<IActionResult> ClearAndInsertRange(Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получение данных на определенную дату
|
/// Получение данных на текущую дату (с пагинацией)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idDiscriminator"></param>
|
||||||
|
/// <param name="request">параметры запроса</param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<ActionResult<PaginationContainer<DataWithWellDepthAndSectionDto>>> GetCurrent(Guid idDiscriminator, SectionPartRequest request, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение данных на определенную дату (с пагинацией)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="idDiscriminator"></param>
|
/// <param name="idDiscriminator"></param>
|
||||||
/// <param name="moment"></param>
|
/// <param name="moment"></param>
|
||||||
|
/// <param name="request">параметры запроса</param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<ActionResult<IEnumerable<DataWithWellDepthAndSectionDto>>> GetByDate(Guid idDiscriminator, DateTimeOffset moment, CancellationToken token);
|
Task<ActionResult<PaginationContainer<DataWithWellDepthAndSectionDto>>> GetByDate(Guid idDiscriminator, DateTimeOffset moment, SectionPartRequest request, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получение исторических данных за определенный период времени
|
/// Получение исторических данных за определенный период времени
|
||||||
@ -86,4 +98,12 @@ public interface IChangeLogApi
|
|||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<ActionResult<int>> DeleteRange(IEnumerable<Guid> ids, CancellationToken token);
|
Task<ActionResult<int>> DeleteRange(IEnumerable<Guid> ids, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение списка дат, в которые происходили изменения (день, месяц, год, без времени)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idDiscriminator"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<ActionResult<IEnumerable<DateOnly>>> GetDatesChange(Guid idDiscriminator, CancellationToken token);
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,13 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Persistence.Models;
|
using Persistence.Models;
|
||||||
using System;
|
using Persistence.Models.Requests;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Persistence.API;
|
namespace Persistence.API;
|
||||||
|
|
||||||
/// Интерфейс для API, предназначенного для работы с табличными данными
|
/// Интерфейс для API, предназначенного для работы с табличными данными
|
||||||
public interface ITableDataApi<TDto, TRequest>
|
public interface ITableDataApi<TDto, TRequest>
|
||||||
where TDto : class, new()
|
where TDto : class, new()
|
||||||
where TRequest : RequestDto
|
where TRequest : Request
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получить страницу списка объектов
|
/// Получить страницу списка объектов
|
||||||
|
114
Persistence/EFExtensions.cs
Normal file
114
Persistence/EFExtensions.cs
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Persistence;
|
||||||
|
public static class EFExtensions
|
||||||
|
{
|
||||||
|
struct TypeAcessor
|
||||||
|
{
|
||||||
|
public LambdaExpression KeySelector { get; set; }
|
||||||
|
public MethodInfo OrderBy { get; set; }
|
||||||
|
public MethodInfo OrderByDescending { get; set; }
|
||||||
|
public MethodInfo ThenBy { get; set; }
|
||||||
|
public MethodInfo ThenByDescending { get; set; }
|
||||||
|
}
|
||||||
|
private static readonly MethodInfo methodOrderBy = GetExtOrderMethod("OrderBy");
|
||||||
|
|
||||||
|
private static readonly MethodInfo methodOrderByDescending = GetExtOrderMethod("OrderByDescending");
|
||||||
|
|
||||||
|
private static readonly MethodInfo methodThenBy = GetExtOrderMethod("ThenBy");
|
||||||
|
|
||||||
|
private static readonly MethodInfo methodThenByDescending = GetExtOrderMethod("ThenByDescending");
|
||||||
|
private static ConcurrentDictionary<Type, Dictionary<string, TypeAcessor>> TypePropSelectors { get; set; } = new();
|
||||||
|
|
||||||
|
private static MethodInfo GetExtOrderMethod(string methodName)
|
||||||
|
=> typeof(System.Linq.Queryable)
|
||||||
|
.GetMethods()
|
||||||
|
.Where(m => m.Name == methodName &&
|
||||||
|
m.IsGenericMethodDefinition &&
|
||||||
|
m.GetParameters().Length == 2 &&
|
||||||
|
m.GetParameters()[1].ParameterType.IsAssignableTo(typeof(LambdaExpression)))
|
||||||
|
.Single();
|
||||||
|
private static Dictionary<string, TypeAcessor> MakeTypeAcessors(Type type)
|
||||||
|
{
|
||||||
|
var propContainer = new Dictionary<string, TypeAcessor>();
|
||||||
|
var properties = type.GetProperties();
|
||||||
|
foreach (var propertyInfo in properties)
|
||||||
|
{
|
||||||
|
var name = propertyInfo.Name.ToLower();
|
||||||
|
ParameterExpression arg = Expression.Parameter(type, "x");
|
||||||
|
MemberExpression property = Expression.Property(arg, propertyInfo.Name);
|
||||||
|
var selector = Expression.Lambda(property, new ParameterExpression[] { arg });
|
||||||
|
var typeAccessor = new TypeAcessor
|
||||||
|
{
|
||||||
|
KeySelector = selector,
|
||||||
|
OrderBy = methodOrderBy.MakeGenericMethod(type, propertyInfo.PropertyType),
|
||||||
|
OrderByDescending = methodOrderByDescending.MakeGenericMethod(type, propertyInfo.PropertyType),
|
||||||
|
ThenBy = methodThenBy.MakeGenericMethod(type, propertyInfo.PropertyType),
|
||||||
|
ThenByDescending = methodThenByDescending.MakeGenericMethod(type, propertyInfo.PropertyType),
|
||||||
|
};
|
||||||
|
|
||||||
|
propContainer.Add(name, typeAccessor);
|
||||||
|
}
|
||||||
|
return propContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Добавить в запрос сортировку по возрастанию или убыванию.
|
||||||
|
/// Этот метод сбросит ранее наложенные сортировки.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TSource"></typeparam>
|
||||||
|
/// <param name="query"></param>
|
||||||
|
/// <param name="propertySort">
|
||||||
|
/// Свойство сортировки.
|
||||||
|
/// Состоит из названия свойства (в любом регистре)
|
||||||
|
/// и опционально указания направления сортировки "asc" или "desc"
|
||||||
|
/// </param>
|
||||||
|
/// <example>
|
||||||
|
/// var query = query("Date desc");
|
||||||
|
/// </example>
|
||||||
|
/// <returns>Запрос с примененной сортировкой</returns>
|
||||||
|
public static IOrderedQueryable<TSource> SortBy<TSource>(
|
||||||
|
this IQueryable<TSource> query,
|
||||||
|
string propertySort)
|
||||||
|
{
|
||||||
|
var parts = propertySort.Split(" ", 2, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
var isDesc = parts.Length >= 2 && parts[1].ToLower().Trim() == "desc";
|
||||||
|
var propertyName = parts[0];
|
||||||
|
|
||||||
|
var newQuery = query.SortBy(propertyName, isDesc);
|
||||||
|
return newQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Добавить в запрос сортировку по возрастанию или убыванию
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TSource"></typeparam>
|
||||||
|
/// <param name="query"></param>
|
||||||
|
/// <param name="propertyName">Название свойства (в любом регистре)</param>
|
||||||
|
/// <param name="isDesc">Сортировать по убыванию</param>
|
||||||
|
/// <returns>Запрос с примененной сортировкой</returns>
|
||||||
|
public static IOrderedQueryable<TSource> SortBy<TSource>(
|
||||||
|
this IQueryable<TSource> query,
|
||||||
|
string propertyName,
|
||||||
|
bool isDesc)
|
||||||
|
{
|
||||||
|
var typePropSelector = TypePropSelectors.GetOrAdd(typeof(TSource), MakeTypeAcessors);
|
||||||
|
var propertyNamelower = propertyName.ToLower();
|
||||||
|
var typeAccessor = typePropSelector[propertyNamelower];
|
||||||
|
|
||||||
|
var genericMethod = isDesc
|
||||||
|
? typeAccessor.OrderByDescending
|
||||||
|
: typeAccessor.OrderBy;
|
||||||
|
|
||||||
|
var newQuery = (IOrderedQueryable<TSource>)genericMethod
|
||||||
|
.Invoke(genericMethod, new object[] { query, typeAccessor.KeySelector })!;
|
||||||
|
return newQuery;
|
||||||
|
}
|
||||||
|
}
|
@ -1,23 +1,25 @@
|
|||||||
namespace Persistence.Models;
|
namespace Persistence.Models.Requests;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Контейнер для поддержки постраничного просмотра таблиц
|
/// Контейнер для поддержки постраничного просмотра таблиц
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
public class RequestDto
|
public class Request
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Кол-во записей пропущенных с начала таблицы в запросе от api
|
/// Кол-во записей пропущенных с начала таблицы в запросе от api
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Skip { get; set; }
|
public int? Skip { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Кол-во записей в запросе от api
|
/// Кол-во записей в запросе от api
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Take { get; set; }
|
public int? Take { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Настройки сортировки
|
/// Сортировки:
|
||||||
|
/// Содержат список названий полей сортировки
|
||||||
|
/// Указать направление сортировки можно через пробел "asc" или "desc"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string SortSettings { get; set; } = string.Empty;
|
public string SortSettings { get; set; } = string.Empty;
|
||||||
}
|
}
|
22
Persistence/Models/Requests/SectionPartRequest.cs
Normal file
22
Persistence/Models/Requests/SectionPartRequest.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
namespace Persistence.Models.Requests;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Запрос для фильтрации данных по секции и глубине
|
||||||
|
/// </summary>
|
||||||
|
public class SectionPartRequest : Request
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Глубина забоя на дату начала интервала
|
||||||
|
/// </summary>
|
||||||
|
public double? DepthStart { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Глубина забоя на дату окончания интервала
|
||||||
|
/// </summary>
|
||||||
|
public double? DepthEnd { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ключ секции
|
||||||
|
/// </summary>
|
||||||
|
public Guid? IdSection { get; set; }
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using Persistence.Models;
|
using Persistence.Models;
|
||||||
|
using Persistence.Models.Requests;
|
||||||
|
|
||||||
namespace Persistence.Repositories;
|
namespace Persistence.Repositories;
|
||||||
|
|
||||||
@ -19,31 +20,22 @@ public interface IChangeLogRepository //: ISyncRepository<TDto>
|
|||||||
Task<int> InsertRange(Guid idUser, Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token);
|
Task<int> InsertRange(Guid idUser, Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Редактирование записей
|
/// Пометить записи как удаленные
|
||||||
/// </summary>
|
|
||||||
/// <param name="idUser">пользователь, который редактирует</param>
|
|
||||||
/// <param name="idDiscriminator"></param>
|
|
||||||
/// <param name="dtos"></param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<int> UpdateRange(Guid idUser, Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Добавляет Dto у которых id == 0, изменяет dto у которых id != 0
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="idUser">пользователь, который редактирует или добавляет</param>
|
|
||||||
/// <param name="dtos"></param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<int> UpdateOrInsertRange(int idUser, IEnumerable<IDictionary<string, object>> dtos, CancellationToken token);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Помечает записи как удаленные
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="idUser"></param>
|
/// <param name="idUser"></param>
|
||||||
|
/// <param name="ids">ключи записей</param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<int> Clear(Guid idUser, Guid idDiscriminator, CancellationToken token);
|
Task<int> MarkAsDeleted(Guid idUser, IEnumerable<Guid> ids, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Пометить записи как удаленные
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idUser"></param>
|
||||||
|
/// <param name="idDiscriminator">дискриминатор таблицы</param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<int> MarkAsDeleted(Guid idUser, Guid idDiscriminator, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Очистить и добавить новые
|
/// Очистить и добавить новые
|
||||||
@ -56,21 +48,24 @@ public interface IChangeLogRepository //: ISyncRepository<TDto>
|
|||||||
Task<int> ClearAndInsertRange(Guid idUser, Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token);
|
Task<int> ClearAndInsertRange(Guid idUser, Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Пометить записи как удаленные
|
/// Редактирование записей
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="idUser"></param>
|
/// <param name="idUser">пользователь, который редактирует</param>
|
||||||
/// <param name="ids"></param>
|
/// <param name="idDiscriminator"></param>
|
||||||
|
/// <param name="dtos"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<int> MarkAsDeleted(Guid idUser, IEnumerable<Guid> ids, CancellationToken token);
|
Task<int> UpdateRange(Guid idUser, Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получение дат изменений записей
|
/// Получение актуальных записей на определенный момент времени (с пагинацией)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="request"></param>
|
/// <param name="idDiscriminator"></param>
|
||||||
|
/// <param name="moment">текущий момент времени</param>
|
||||||
|
/// <param name="request">параметры запроса</param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<IEnumerable<DateOnly>> GetDatesChange(CancellationToken token);
|
Task<PaginationContainer<DataWithWellDepthAndSectionDto>> GetByDate(Guid idDiscriminator, DateTimeOffset moment, SectionPartRequest request, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получение измененных записей за период времени
|
/// Получение измененных записей за период времени
|
||||||
@ -83,11 +78,10 @@ public interface IChangeLogRepository //: ISyncRepository<TDto>
|
|||||||
Task<IEnumerable<ChangeLogDto>> GetChangeLogForDate(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token);
|
Task<IEnumerable<ChangeLogDto>> GetChangeLogForDate(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получение актуальных записей на определенный момент времени
|
/// Получение списка дат, в которые происходили изменения (день, месяц, год, без времени)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="idDiscriminator"></param>
|
/// <param name="idDiscriminator"></param>
|
||||||
/// <param name="moment">текущий момент времени</param>
|
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<IEnumerable<DataWithWellDepthAndSectionDto>> GetByDate(Guid idDiscriminator, DateTimeOffset moment, CancellationToken token);
|
Task<IEnumerable<DateOnly>> GetDatesChange(Guid idDiscriminator, CancellationToken token);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using Persistence.Models;
|
using Persistence.Models.Requests;
|
||||||
|
|
||||||
namespace Persistence.Repositories;
|
namespace Persistence.Repositories;
|
||||||
|
|
||||||
@ -7,7 +7,7 @@ namespace Persistence.Repositories;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ITableDataRepository<TDto, TRequest>
|
public interface ITableDataRepository<TDto, TRequest>
|
||||||
where TDto : class, new()
|
where TDto : class, new()
|
||||||
where TRequest : RequestDto
|
where TRequest : Request
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получить страницу списка объектов
|
/// Получить страницу списка объектов
|
||||||
|
Loading…
Reference in New Issue
Block a user