using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;
using System.Reflection;
using System.Security.Principal;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using AutoMapper.Internal;
using DocumentFormat.OpenXml.Math;
using DocumentFormat.OpenXml.Office2010.ExcelAc;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml.Vml.Office;
using DocumentFormat.OpenXml.Wordprocessing;
using EFCore.BulkExtensions;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Caching;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.EventBus.Local;
using Volo.Abp.SettingManagement;
using Volo.Abp.Uow;
using Win_in.Sfs.Basedata.Application.Contracts;
using Win_in.Sfs.Shared.Application.Contracts;
using Win_in.Sfs.Shared.Application.Contracts.ExportAndImport;
using Win_in.Sfs.Shared.Domain;
using Win_in.Sfs.Shared.Domain.Shared;
using Win_in.Sfs.Shared.Event;
namespace Win_in.Sfs.Shared.Application;
///
/// 应用服务基类
///
public abstract class SfsCrudWithDetailsAppServiceBase
: CrudAppService
, ISfsCrudWithDetailsAppService
, ISfsGetByNumberAppService
where TEntity : class, IEntity
where TEntityDto : class, IEntityDto, new()
where TRequestInput : SfsRequestInputBase
where TDetail : SfsDetailEntityBase
where TDetailDTO : class, new()
where TImportInput : class, new()
{
protected readonly ISfsRepositoryBase _repository;
///
/// 实体名称
///
protected readonly string EntityClassName = typeof(TEntity).Name;
protected SfsCrudWithDetailsAppServiceBase(ISfsRepositoryBase repository) : base(repository)
{
_repository = repository;
}
protected IDistributedCache Cache => LazyServiceProvider.LazyGetRequiredService>();
protected IDocumentSettingAppService DocumentSettingAppService => LazyServiceProvider.LazyGetRequiredService();
protected IExportImportService ExportImportService => LazyServiceProvider.LazyGetRequiredService();
protected IHttpContextAccessor HttpContextAccessor => LazyServiceProvider.LazyGetRequiredService();
protected ILocalEventBus LocalEventBus => LazyServiceProvider.LazyGetRequiredService();
///
///
///
protected ISettingManager SettingManager => LazyServiceProvider.LazyGetRequiredService();
///
/// 添加明细列表
///
/// 实体Id
/// 明细列表
[HttpPost("details/")]
public virtual async Task AddDetailListAsync(Guid id, List list)
{
var entity = await _repository.GetAsync(id).ConfigureAwait(false);
Check.NotNull(entity, EntityClassName);
var details = ObjectMapper.Map, List>(list);
if (entity is SfsMasterAggregateRootBase masterEntity)
{
masterEntity.AddDetails(details);
}
}
///
/// 新增实体
///
/// CreateInput
[HttpPost("")]
public override async Task CreateAsync(TCreateInput input)
{
await CheckCreatePolicyAsync().ConfigureAwait(continueOnCapturedContext: false);
var entity = input.ToObject();
SetIdForGuids(entity);
TryToSetTenantId(entity);
await Repository.InsertAsync(entity, autoSave: true).ConfigureAwait(continueOnCapturedContext: false);
var dto = entity.ToObject();
await Cache.SetItemAsync(dto.Id.ToString(), dto, SfsCacheConst.SeveralMinutes).ConfigureAwait(false);
return dto;
}
///
/// 删除实体
///
/// 实体Id
[HttpDelete("{id}")]
public override async Task DeleteAsync(Guid id)
{
await Repository.DeleteAsync(id).ConfigureAwait(false);
await Cache.DeleteItemAsync(id.ToString()).ConfigureAwait(false);
return;
}
///
/// 删除明细
///
/// 实体Id
/// 明细Id
///
[HttpDelete("details/{id}")]
public virtual async Task DeleteDetailAsync(Guid id, Guid detailId)
{
var entity = await _repository.GetAsync(id).ConfigureAwait(false);
Check.NotNull(entity, EntityClassName);
if (entity is SfsMasterAggregateRootBase masterEntity)
{
masterEntity.RemoveDetail(detailId);
}
}
///
/// 导出数据
///
[HttpPost("export")]
public virtual async Task ExportAsync(TRequestInput input)
{
var expression = input.Condition.Filters?.Count > 0
? input.Condition.Filters.ToLambda()
: p => true;
var entities = await _repository.GetPagedListAsync(expression, input.SkipCount, input.MaxResultCount,
input.Sorting, true).ConfigureAwait(false);
var list = ObjectMapper.Map, List>(entities);
var hasDetails = typeof(TEntity) is SfsMasterAggregateRootBase detailEntity;
return ExportImportService.Export(list, detailsProptyName: hasDetails ? nameof(detailEntity.Details) : null);
}
///
/// 按条件获取全部数据列表
///
/// RequestInput
/// 是否包含明细
///
///
[HttpPost("get-all")]
public virtual async Task> GetAllListByFilterAsync(TRequestInput sfsRequestInput, bool includeDetails = false,
CancellationToken cancellationToken = default)
{
Expression> expression = sfsRequestInput.Condition.Filters?.Count > 0
? sfsRequestInput.Condition.Filters.ToLambda()
: p => true;
return await GetAllListAsync(expression, sfsRequestInput.Sorting, includeDetails, cancellationToken).ConfigureAwait(false);
}
///
/// 按Id获取实体
///
/// 实体Id
///
[HttpGet("{id}")]
public override async Task GetAsync(Guid id)
{
var dto = await Cache.GetOrAddItemAsync(
id.ToString(),
async () => await base.GetAsync(id).ConfigureAwait(false),
SfsCacheConst.SeveralMinutes).ConfigureAwait(false);
return dto;
}
///
/// 按编号获取实体
///
/// 编号
///
[HttpGet("by-number")]
public virtual async Task GetByNumberAsync(string number)
{
var entity = (await _repository.GetQueryableAsync().ConfigureAwait(false)).Where("Number=@0", number).FirstOrDefault();
var dto = ObjectMapper.Map(entity);
return dto;
}
///
/// 按条件获取数量
/// request sample
/// {
/// "maxResultCount": 1000,
/// "skipCount": 0,
/// "sorting": "",
/// "condition": { "filters": []}
/// }
///
/// RequestInput
///
///
[HttpPost("count")]
public virtual async Task GetCountByFilterAsync(TRequestInput sfsRequestInput, CancellationToken cancellationToken = default)
{
Expression> expression = sfsRequestInput.Condition.Filters?.Count > 0
? sfsRequestInput.Condition.Filters.ToLambda()
: p => true;
var count = await _repository.GetCountAsync(expression, cancellationToken).ConfigureAwait(false);
return count;
}
///
/// 获取明细
///
/// 实体Id
/// 明细Id
///
[HttpGet("details/{id}")]
public virtual async Task GetDetailAsync(Guid id, Guid detailId)
{
var entity = await _repository.GetAsync(id).ConfigureAwait(false);
Check.NotNull(entity, EntityClassName);
if (entity is SfsMasterAggregateRootBase masterEntity)
{
var detail = masterEntity.GetDetail(detailId);
var dto = ObjectMapper.Map(detail);
return dto;
}
return null;
}
///
/// 按条件获取明细列表
///
/// 实体Id
/// 明细RequestInput
///
[HttpGet("details/")]
public virtual async Task> GetDetailListAsync(Guid id, TDetailRequestInput requestInput)
{
var entity = await _repository.GetAsync(id).ConfigureAwait(false);
Check.NotNull(entity, EntityClassName);
if (entity is SfsMasterAggregateRootBase masterEntity)
{
var details = masterEntity.GetDetailList(d => d.MasterID == id).ToList();
var dtos = ObjectMapper.Map, List>(details);
return dtos;
}
return null;
}
///
/// 屏蔽基类方法
///
///
///
[NonAction]
public override async Task> GetListAsync(TRequestInput input)
{
return await base.GetListAsync(input).ConfigureAwait(false);
}
///
/// 按条件获取分页列表
/// request sample
/// {
/// "maxResultCount": 1000,
/// "skipCount": 0,
/// "sorting": "",
/// "condition": { "filters": []}
/// }
///
/// RequestInput
/// 是否包含明细
///
///
[HttpPost("list")]
public virtual async Task> GetPagedListByFilterAsync(TRequestInput sfsRequestInput, bool includeDetails = false,
CancellationToken cancellationToken = default)
{
Expression> expression = sfsRequestInput.Condition.Filters?.Count > 0
? sfsRequestInput.Condition.Filters.ToLambda()
: p => true;
return await GetPagedListAsync(expression, sfsRequestInput.SkipCount, sfsRequestInput.MaxResultCount, sfsRequestInput.Sorting, includeDetails, cancellationToken).ConfigureAwait(false);
}
///
/// 按关键字获取分页列表
///
/// 关键字
/// 跳过数
/// 最大结果数
/// 排序
/// 是否包含明细
///
///
[HttpPost("search")]
public virtual async Task> GetPagedListByKeyWordAsync(string keyWord, int skipCount, int maxResultCount, string sorting,
bool includeDetails = false, CancellationToken cancellationToken = default)
{
var expression = BuildSearchExpression(keyWord);
return await GetPagedListAsync(expression, skipCount, maxResultCount, sorting, includeDetails, cancellationToken).ConfigureAwait(false);
}
///
/// 导入数据
///
[HttpPost("import")]
[Consumes("multipart/form-data")]
[UnitOfWork]
public virtual async Task ImportAsync([FromForm] SfsImportRequestInput requestInput, [Required] IFormFile file)
{
using var ms = new MemoryStream();
await file.OpenReadStream().CopyToAsync(ms).ConfigureAwait(false);
var inputFileBytes = ms.GetAllBytes();
var result = await ImportInternalAsync(requestInput, inputFileBytes);
var bytes = result.FileContents;
result.FileContents = null;
HttpContextAccessor.HttpContext.Response.Headers.AccessControlExposeHeaders="X-Response";
HttpContextAccessor.HttpContext.Response.Headers.Add("X-Response",
JsonSerializer.Serialize(new { result.ExceptionMessage, result.FileName, result.FileCode, result }));
Console.WriteLine(@"导入错误信息:"+result.ExceptionMessage);
var resultAction = new TestResult(bytes, ExportImportService.ContentType) { FileDownloadName = result.FileName };
resultAction.errorNum = result.ErrorNum;
resultAction.successNum = resultAction.successNum;
return resultAction;
}
public class TestResult: FileContentResult
{
public byte[]_bytes { get; set; }
public int errorNum { get; set; }
public int successNum { get; set; }
public TestResult([NotNull] byte[] fileContents, [NotNull] string contentType) : base(fileContents, contentType)
{
}
public TestResult([NotNull] byte[] fileContents, [NotNull] MediaTypeHeaderValue contentType) : base(fileContents, contentType)
{
}
}
///
/// 获取导入模板
///
[HttpPost("import-template")]
public virtual IActionResult ImportTemplateAsync()
{
return ExportImportService.GetImportTemplate();
}
///
/// 修改实体
///
/// 实体Id
/// UpdateInput
///
[HttpPut("{id}")]
public override async Task UpdateAsync(Guid id, TCreateInput input)
{
try
{
//Value Inject 替换 AutoMapper
await CheckUpdatePolicyAsync().ConfigureAwait(continueOnCapturedContext: false);
TEntity entity = await GetEntityByIdAsync(id).ConfigureAwait(continueOnCapturedContext: false);
entity.FromObject(input);
await Repository.UpdateAsync(entity, autoSave: true).ConfigureAwait(continueOnCapturedContext: false);
var dto = entity.ToObject();
await Cache.SetItemAsync(dto.Id.ToString(), dto, SfsCacheConst.SeveralMinutes).ConfigureAwait(false);
return dto;
}
catch (Exception ex)
{
var message = ex.Message.Contains("Database operation expected to affect 1 row(s) but actually affected 0 row(s)")
? $" {typeof(TEntityDto).Name} 已经被他人更改, 请刷新数据后再更新."
: ex.ToString();
throw new UserFriendlyException(message);
}
}
///
/// 更新明细
///
/// 实体Id
/// 明细Id
/// 明细UpdateDto
///
[HttpPut("details/{id}")]
public virtual async Task UpdateDetailAsync(Guid id, Guid detailId, TDetailDTO updateDTO)
{
var entity = await _repository.GetAsync(id).ConfigureAwait(false);
Check.NotNull(entity, EntityClassName);
var detail = ObjectMapper.Map(updateDTO);
if (entity is SfsMasterAggregateRootBase masterEntity)
{
masterEntity.ReplaceDetail(detailId, detail);
}
}
///
/// 构造搜索条件表达式
///
/// 搜索关键字
///
protected virtual Expression> BuildSearchExpression(string keyWord)
{
// p => p.Id.ToString().Contains(keyWord);
var expression = typeof(TEntity).GetExpressionByProperty("Number", keyWord);
return expression;
}
protected virtual async Task GenerateNumberAsync(string typeName, DateTime time)
{
var documentInput = new DocumentSettingGenerateInput(typeName, Clock.Normalize(time));
var maxCount = 10_000;
var tryCount = 0;
while (true)
{
var number = await DocumentSettingAppService.GenerateNumberAsync(documentInput).ConfigureAwait(false);
var entity = await GetByNumberAsync(number).ConfigureAwait(false);
if (entity == null)
{
return number;
}
tryCount++;
if (tryCount >= maxCount)
{
throw new UserFriendlyException($"无法生成 {documentInput.Type} 在 {documentInput.Time} 单据编号,请联系管理员处理。");
}
}
}
///
/// 按表达式条件获取分页列表
///
///
///
///
///
///
protected async Task> GetAllListAsync(Expression> expression, string sorting, bool includeDetails,
CancellationToken cancellationToken)
{
var entities = await _repository.GetListAsync(expression, sorting, includeDetails, cancellationToken).ConfigureAwait(false);
var dtos = ObjectMapper.Map, List>(entities);
return dtos;
}
///
/// 导入查询实体,可重写
///
///
///
protected virtual async Task GetEntityAsync(TImportInput importInput)
{
var source = await _repository.GetDbSetAsync().ConfigureAwait(false);
return source.AsQueryable().WhereByKey(importInput)?.FirstOrDefault();
}
///
/// 按表达式条件获取分页列表
///
///
///
///
///
///
///
///
protected async Task> GetPagedListAsync(Expression> expression, int skipCount, int maxResultCount, string sorting, bool includeDetails,
CancellationToken cancellationToken)
{
var totalCount = await _repository.GetCountAsync(expression, cancellationToken).ConfigureAwait(false);
var entities = await _repository.GetPagedListAsync(expression, skipCount, maxResultCount, sorting, includeDetails, cancellationToken).ConfigureAwait(false);
var dtos = ObjectMapper.Map, List>(entities);
return new PagedResultDto(totalCount, dtos);
}
///
/// 导入数据具体实现,可重写
///
[UnitOfWork]
protected virtual async Task ImportInternalAsync(SfsImportRequestInput requestInput, byte[] inputFileBytes)
{
try
{
var hasDetails = typeof(TEntity).GetInterfaces().Any(o => o.IsGenericType && o.GetGenericTypeDefinition() == typeof(IMasterEntity<>));
var modelList = ExportImportService.Import(inputFileBytes);
var modelDict = new Dictionary>();
var entityDict = new Dictionary();
foreach (var model in modelList)
{
// DataAnnotations 静态验证
var validationRresults = new List();
modelDict.Add(model, validationRresults);
Validator.TryValidateObject(model, new ValidationContext(model, null, null), validationRresults);
}
// 如果没有验证错误或允许部分导入
if (!modelDict.SelectMany(o => o.Value).Any() || requestInput.IsAllowPartImport)
{
// 遍历并处理导入
if (hasDetails) //
{
var groups = modelList.AsQueryable().GroupByKey();
foreach (var item in groups)
{
var model = item.ToList().FirstOrDefault();
var validationRresults = modelDict[model];
await ImportValidationAsync(requestInput, modelDict, entityDict, model, validationRresults, item.ToList()).ConfigureAwait(false);
}
}
else
{
foreach (var item in modelDict)
{
var model = item.Key;
var validationRresults = item.Value;
await ImportValidationAsync(requestInput, modelDict, entityDict, model, validationRresults).ConfigureAwait(false);
}
}
}
// 批量更新
if (entityDict.Any())
{
entityDict=await ImportProcessingEntityAsync(entityDict).ConfigureAwait(false);
// 调用批量验证
var entityListStatus = await ValidateImportEntities(entityDict).ConfigureAwait(false);
if (entityListStatus)
{
await SaveImportAsync(entityDict).ConfigureAwait(false);
}
}
//将需要新增的数据进行发布
var addList= entityDict.Where(p => p.Value == EntityState.Added).Select(p=>p.Key).ToList();
await PublishCreatedAsync(addList).ConfigureAwait(false);
// 创建导入报告
var reportFile = ExportImportService.GetImportReport(inputFileBytes, modelDict);
// 创建返回值
return new SfsImportResult
{
TotalNum = modelList.Count,
ErrorNum = modelDict.Count(o => o.Value.Any()),
FileName = reportFile.FileDownloadName,
FileContents = reportFile.FileContents
};
}
catch (Exception ex)
{
Logger.LogException(ex);
return new SfsImportResult() { ExceptionMessage = ex.Message };
}
}
///
/// 发布新增事件
///
///
///
private async Task PublishCreatedAsync(List entities)
{
try
{
await LocalEventBus.PublishAsync(new SfsCreatedEntityEventData>(entities),false).ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.LogDebug($"{typeof(TEntity).Name} Created Event:{ex.Message}", null);
Console.WriteLine(ex.Source);
throw;
}
}
///
/// 用来重写 导入数据时可以加工数据
///
///
///
protected virtual async Task> ImportProcessingEntityAsync(Dictionary dictionary)
{
return dictionary;
}
///
/// 导入保存到数据库,可重写
///
protected virtual async Task SaveImportAsync(Dictionary dict)
{
var entityList = dict.Keys.ToList();
var context = await _repository.GetDbContextAsync().ConfigureAwait(false);
var list = new List();
if (entityList.Count > 0)
{
foreach (var entity in entityList)
{
foreach (var propertyInfo in entity.GetType().GetProperties())
{
if (propertyInfo.PropertyType.IsListType() && propertyInfo.Name == "Details")
{
var entityDetails= propertyInfo.GetValue(entity, null);
list.AddRange(((List)entityDetails)!);
}
}
}
var bulkConfig = new BulkConfig()
{
SetOutputIdentity = true,
PreserveInsertOrder = true
};
await context.BulkInsertOrUpdateAsync(entityList, bulkConfig).ConfigureAwait(false);
await context.BulkInsertAsync(list).ConfigureAwait(false);
}
}
///
/// 导入批量验证,可重写
///
protected virtual async Task ValidateImportEntities(Dictionary dict)
{
return await Task.FromResult(true).ConfigureAwait(false);
}
///
/// 导入单个输入,可重写
///
///
///
///
protected virtual async Task ValidateImportModelAsync(TImportInput model, List validationRresult)
{
await Task.CompletedTask.ConfigureAwait(false);
}
///
/// 验证单个实体,可重写
///
///
///
///
///
protected virtual async Task ValidateImportEntityAsync(TImportInput model, TEntity entity, List validationRresult)
{
await Task.CompletedTask.ConfigureAwait(false);
}
private async Task ImportValidationAsync(SfsImportRequestInput requestInput, Dictionary> modelDict, Dictionary entityDict, TImportInput model, List validationRresults, List detailModels = null)
{
var entity = await GetEntityAsync(model).ConfigureAwait(false);
if (requestInput.Method == EnumImportMethod.Append)
{
if (entity != null)
{
validationRresults.Add(new ValidationResult($"无法添加,数据已存在", new string[] { "错误" }));
}
}
else if (requestInput.Method == EnumImportMethod.Update)
{
if (entity == null)
{
validationRresults.Add(new ValidationResult($"无法更新,数据不存在", new string[] { "错误" }));
}
}
// 不包含错误或运行部分插入时,执行动态验证
if (!modelDict.SelectMany(o => o.Value).Any() || requestInput.IsAllowPartImport)
{
var hasEntity = entity != null;
await ValidateImportModelAsync(model, validationRresults).ConfigureAwait(false);
}
// 不包含错误或运行部分插入时,加入批量操作列表
if (!modelDict.SelectMany(o => o.Value).Any() || requestInput.IsAllowPartImport)
{
if (entity is IHasWorker worker)
{
worker.Worker = CurrentUser.GetUserName();
}
var hasEntity = entity != null;
if (entity == null)
{
entity = ObjectMapper.Map(model);
if (entity is SfsMasterAggregateRootBase entityWithIdAndNumber)
{
entityWithIdAndNumber.SetIdAndNumberWithDetails(GuidGenerator, await GenerateNumberAsync(typeof(TEntity).Name, DateTime.Now.Date).ConfigureAwait(false));
}
else if (entity is ISetId entityWithId)
{
entityWithId.SetId(GuidGenerator.Create());
}
if (entity is CreationAuditedAggregateRoot creation)
{
creation.CreationTime = DateTime.Now;
creation.CreatorId = CurrentUser.Id;
}
// 清空现有子表
(entity as SfsMasterAggregateRootBase)?.Details.Clear();
}
else
{
var id = entity.Id;
ObjectMapper.Map(model, entity);
// ObjectMapper.Map 清空了 id,因此需要把预存的 id 取回
if (entity is ISetId entityWithId)
{
entityWithId.SetId(id);
}
}
// 设置子表
if (detailModels != null && entity is SfsMasterAggregateRootBase masterEntity)
{
foreach (var item in detailModels)
{
var detail = ObjectMapper.Map(item);
masterEntity.Details.Add(detail);
if (detail is ISetId entityWithId)
{
entityWithId.SetId(GuidGenerator.Create());
}
detail.SetIdAndNumber(GuidGenerator, masterEntity.Id, masterEntity.Number);
if (detail is CreationAuditedAggregateRoot creation)
{
creation.CreationTime = DateTime.Now;
creation.CreatorId = CurrentUser.Id;
}
}
}
await ValidateImportEntityAsync(model, entity, validationRresults).ConfigureAwait(false);
entityDict.Add(entity, hasEntity ? EntityState.Modified : EntityState.Added);
}
}
}