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(); } }