using CsvHelper; using Microsoft.Net.Http.Headers; using NetAdmin.Application.Repositories; using NetAdmin.Domain; using NetAdmin.Domain.Dto.Dependency; namespace NetAdmin.Application.Services; /// /// 仓储服务基类 /// /// 实体类型 /// 主键类型 /// 日志类型 public abstract class RepositoryService(BasicRepository rpo) : ServiceBase where TEntity : EntityBase // where TPrimary : IEquatable { /// /// 默认仓储 /// protected BasicRepository Rpo => rpo; /// /// 启用级联保存 /// protected bool EnableCascadeSave { get => Rpo.DbContextOptions.EnableCascadeSave; set => Rpo.DbContextOptions.EnableCascadeSave = value; } /// /// 导出实体 /// protected static async Task ExportAsync( // Func, ISelectGrouping> selector, QueryReq query, string fileName , Expression, object>> listExp = null) where TQuery : DataAbstraction, new() { var list = await selector(query).Take(Numbers.MAX_LIMIT_EXPORT).ToListAsync(listExp).ConfigureAwait(false); return await GetExportFileStreamAsync(fileName, list).ConfigureAwait(false); } /// /// 导出实体 /// protected static async Task ExportAsync( // Func, ISelect> selector, QueryReq query, string fileName , Expression> listExp = null) where TQuery : DataAbstraction, new() { var select = selector(query) #if DBTYPE_SQLSERVER .WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait) #endif .Take(Numbers.MAX_LIMIT_EXPORT); object list = listExp == null ? await select.ToListAsync().ConfigureAwait(false) : await select.ToListAsync(listExp).ConfigureAwait(false); return await GetExportFileStreamAsync(fileName, list).ConfigureAwait(false); } /// /// 更新实体 /// /// 新的值 /// 包含的属性 /// 排除的属性 /// 查询表达式 /// 查询sql /// 是否忽略版本锁 /// 更新行数 protected Task UpdateAsync( // TEntity newValue // , IEnumerable includeFields // , string[] excludeFields = null // , Expression> whereExp = null // , string whereSql = null // , bool ignoreVersion = false) { // 默认匹配主键 whereExp ??= a => a.Id.Equals(newValue.Id); var update = BuildUpdate(newValue, includeFields, excludeFields, ignoreVersion).Where(whereExp).Where(whereSql); return update.ExecuteAffrowsAsync(); } #if DBTYPE_SQLSERVER /// /// 更新实体 /// /// 新的值 /// 包含的属性 /// 排除的属性 /// 查询表达式 /// 查询sql /// 是否忽略版本锁 /// 更新后的实体列表 protected Task> UpdateReturnListAsync( // TEntity newValue // , IEnumerable includeFields // , string[] excludeFields = null // , Expression> whereExp = null // , string whereSql = null // , bool ignoreVersion = false) { // 默认匹配主键 whereExp ??= a => a.Id.Equals(newValue.Id); return BuildUpdate(newValue, includeFields, excludeFields, ignoreVersion) .Where(whereExp) .Where(whereSql) .ExecuteUpdatedAsync(); } #endif private static async Task GetExportFileStreamAsync(string fileName, object list) { var listTyped = list.Adapt>(); var stream = new MemoryStream(); var writer = new StreamWriter(stream); var csv = new CsvWriter(writer, CultureInfo.InvariantCulture); csv.WriteHeader(); await csv.NextRecordAsync().ConfigureAwait(false); foreach (var item in listTyped) { csv.WriteRecord(item); await csv.NextRecordAsync().ConfigureAwait(false); } await csv.FlushAsync().ConfigureAwait(false); _ = stream.Seek(0, SeekOrigin.Begin); App.HttpContext.Response.Headers.ContentDisposition = new ContentDispositionHeaderValue(Chars.FLG_HTTP_HEADER_VALUE_ATTACHMENT) { FileNameStar = $"{fileName}_{DateTime.Now:yyyy.MM.dd-HH.mm.ss}.csv" }.ToString(); return new FileStreamResult(stream, Chars.FLG_HTTP_HEADER_VALUE_APPLICATION_OCTET_STREAM); } private IUpdate BuildUpdate( // TEntity entity // , IEnumerable includeFields // , string[] excludeFields = null // , bool ignoreVersion = false) { var updateExp = includeFields == null ? Rpo.UpdateDiy.SetSource(entity) : Rpo.UpdateDiy.SetDto(includeFields!.ToDictionary( x => x , x => typeof(TEntity).GetProperty(x, BindingFlags.Public | BindingFlags.Instance)! .GetValue(entity))); if (excludeFields != null) { updateExp = updateExp.IgnoreColumns(excludeFields); } if (!ignoreVersion && entity is IFieldVersion ver) { updateExp = updateExp.Where($"{nameof(IFieldVersion.Version)} = @version", new { version = ver.Version }); } return updateExp; } }