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; namespace AsbCloudInfrastructure.Repository { #nullable enable /// <summary> /// CRUD сервис для работы с БД /// </summary> /// <typeparam name="TDto"></typeparam> /// <typeparam name="TEntity"></typeparam> public class CrudServiceBase<TDto, TEntity> : ICrudService<TDto> where TDto : AsbCloudApp.Data.IId where TEntity : class, IId { protected readonly IAsbCloudDbContext dbContext; protected readonly DbSet<TEntity> dbSet; protected readonly Func<IQueryable<TEntity>> GetQuery; public CrudServiceBase(IAsbCloudDbContext context) { dbContext = context; dbSet = context.Set<TEntity>(); GetQuery = () => dbSet; } public CrudServiceBase(IAsbCloudDbContext dbContext, ISet<string> includes) { this.dbContext = dbContext; dbSet = dbContext.Set<TEntity>(); GetQuery = () => { IQueryable<TEntity> query = dbSet; foreach (var include in includes) query = query.Include(include); return query; }; } public CrudServiceBase(IAsbCloudDbContext context, Func<DbSet<TEntity>, IQueryable<TEntity>> makeQuery) { dbContext = context; dbSet = context.Set<TEntity>(); GetQuery = () => makeQuery(dbSet); } /// <inheritdoc/> public virtual async Task<IEnumerable<TDto>> GetAllAsync(CancellationToken token = default) { var entities = await GetQuery() //.OrderBy(e => e.Id) .AsNoTracking() .ToListAsync(token) .ConfigureAwait(false); var dtos = entities.Select(Convert).ToList(); return dtos; } /// <inheritdoc/> public virtual async Task<TDto?> GetOrDefaultAsync(int id, CancellationToken token = default) { var entity = await GetQuery() .AsNoTracking() .FirstOrDefaultAsync(e => e.Id == id, token) .ConfigureAwait(false); if (entity == default) return default; var dto = Convert(entity); return dto; } /// <inheritdoc/> 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; } /// <inheritdoc/> public virtual async Task<int> InsertAsync(TDto item, CancellationToken token = default) { var entity = Convert(item); entity.Id = 0; var entry = dbSet.Add(entity); await dbContext.SaveChangesAsync(token); entry.State = EntityState.Detached; return entity.Id; } /// <inheritdoc/> public virtual async Task<int> InsertRangeAsync(IEnumerable<TDto> items, CancellationToken token = default) { if (!items.Any()) return 0; var entities = items.Select(i => { var entity = Convert(i); entity.Id = 0; return entity; }); var entries = new List<Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry>(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; } /// <inheritdoc/> public virtual async Task<int> UpdateAsync(TDto item, CancellationToken token = default) { var existingEntity = await dbSet .AsNoTracking() .FirstOrDefaultAsync(e => e.Id == item.Id, token) .ConfigureAwait(false); if (existingEntity is null) return ICrudService<TDto>.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<int> UpdateRangeAsync(IEnumerable<TDto> dtos, CancellationToken token) { var ids = dtos.Select(d => d.Id); var existingEntities = await dbSet .AsNoTracking() .Where(d => ids.Contains(d.Id)) .Select(d => d.Id) .ToListAsync(token) .ConfigureAwait(false); if (ids.Count() > existingEntities.Count) return ICrudService<TDto>.ErrorIdNotFound; foreach (var dto in dtos) { var entity = Convert(dto); var entry = dbSet.Update(entity); } var affected = await dbContext.SaveChangesAsync(token); return affected; } /// <inheritdoc/> public virtual Task<int> DeleteAsync(int id, CancellationToken token = default) { var entity = dbSet .AsNoTracking() .FirstOrDefault(e => e.Id == id); if (entity == default) return Task.FromResult(ICrudService<TDto>.ErrorIdNotFound); var entry = dbSet.Remove(entity); var affected = dbContext.SaveChangesAsync(token); entry.State = EntityState.Detached; return affected; } protected virtual TDto Convert(TEntity src) => src.Adapt<TDto>(); protected virtual TEntity Convert(TDto src) => src.Adapt<TEntity>(); } #nullable disable }