using AsbCloudApp.Services;
using AsbCloudDb.Model;
using Mapster;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Exceptions;
using Microsoft.EntityFrameworkCore.ChangeTracking;
namespace AsbCloudInfrastructure.Repository;
///
/// CRUD сервис для работы с БД
///
///
///
public class CrudRepositoryBase : QueryContainer, ICrudRepository
where TDto : AsbCloudApp.Data.IId
where TEntity : class, IId
{
public CrudRepositoryBase(IAsbCloudDbContext context)
: base(context)
{ }
public CrudRepositoryBase(IAsbCloudDbContext context, Func, IQueryable> makeQuery)
: base(context, makeQuery)
{ }
///
public virtual async Task> GetAllAsync(CancellationToken token)
{
var entities = await GetQuery()
.AsNoTracking()
.ToListAsync(token)
.ConfigureAwait(false);
var dtos = entities.Select(Convert).ToList();
return dtos;
}
///
public virtual async Task GetOrDefaultAsync(int id, CancellationToken token)
{
var entity = await GetQuery()
.AsNoTracking()
.FirstOrDefaultAsync(e => e.Id == id, token)
.ConfigureAwait(false);
if (entity == default)
return default;
var dto = Convert(entity);
return dto;
}
///
public virtual TDto? GetOrDefault(int id)
{
var entity = GetQuery()
.AsNoTracking()
.FirstOrDefault(e => e.Id == id);
if (entity == default)
return default;
var dto = Convert(entity);
return dto;
}
///
public virtual async Task InsertAsync(TDto item, CancellationToken token)
{
var entity = Convert(item);
entity.Id = 0;
var entry = dbSet.Add(entity);
await dbContext.SaveChangesAsync(token);
entry.State = EntityState.Detached;
return entity.Id;
}
///
public virtual async Task InsertRangeAsync(IEnumerable items, CancellationToken token)
{
if (!items.Any())
return 0;
var entities = items.Select(i =>
{
var entity = Convert(i);
entity.Id = 0;
return entity;
});
var entries = new List(items.Count());
foreach (var entity in entities)
{
var entry = dbSet.Add(entity);
entries.Add(entry);
}
var affected = await dbContext.SaveChangesAsync(token);
entries.ForEach(e => e.State = EntityState.Detached);
return affected;
}
///
public virtual async Task UpdateAsync(TDto item, CancellationToken token)
{
var existingEntity = await dbSet
.AsNoTracking()
.FirstOrDefaultAsync(e => e.Id == item.Id, token)
.ConfigureAwait(false);
if (existingEntity is null)
return ICrudRepository.ErrorIdNotFound;
var entity = Convert(item);
var entry = dbSet.Update(entity);
await dbContext.SaveChangesAsync(token);
entry.State = EntityState.Detached;
return entry.Entity.Id;
}
public virtual async Task UpdateRangeAsync(IEnumerable dtos, CancellationToken token)
{
if (!dtos.Any())
return 0;
var ids = dtos
.Select(o => o.Id)
.Distinct()
.ToArray();
if (ids.Any(id => id == default))
throw new ArgumentInvalidException(nameof(dtos), "Все записи должны иметь Id");
if (ids.Length != dtos.Count())
throw new ArgumentInvalidException(nameof(dtos), "Все записи должны иметь уникальные Id");
var existingEntitiesCount = await dbContext.Set()
.Where(o => ids.Contains(o.Id))
.CountAsync(token);
if (ids.Length != existingEntitiesCount)
throw new ArgumentInvalidException(nameof(dtos), "Все записи должны существовать в БД");
var entities = dtos.Select(Convert);
var entries = entities.Select(entity => dbContext.Set().Update(entity)).ToList();
var affected = await dbContext.SaveChangesAsync(token);
entries.ForEach(entry => entry.State = EntityState.Detached);
return affected;
}
///
public virtual Task DeleteAsync(int id, CancellationToken token)
{
var entity = dbSet
.AsNoTracking()
.FirstOrDefault(e => e.Id == id);
if (entity == default)
return Task.FromResult(ICrudRepository.ErrorIdNotFound);
dbSet.Remove(entity);
var affected = dbContext.SaveChangesAsync(token);
return affected;
}
public virtual async Task DeleteRangeAsync(IEnumerable ids, CancellationToken token)
{
if (!ids.Any())
return 0;
var countExistingEntities = await dbSet
.Where(d => ids.Contains(d.Id))
.CountAsync(token);
if (ids.Count() > countExistingEntities)
return ICrudRepository.ErrorIdNotFound;
var entities = dbContext.Set().Where(e => ids.Contains(e.Id));
dbContext.Set().RemoveRange(entities);
return await dbContext.SaveChangesAsync(token);
}
protected virtual TDto Convert(TEntity src) => src.Adapt();
protected virtual TEntity Convert(TDto src) => src.Adapt();
}