You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

765 lines
30 KiB

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;
/// <summary>
/// 应用服务基类
/// </summary>
public abstract class SfsCrudWithDetailsAppServiceBase<TEntity, TEntityDto, TRequestInput, TCreateInput,
TDetail, TDetailDTO, TDetailRequestInput, TImportInput>
: CrudAppService<TEntity, TEntityDto, Guid, TRequestInput, TCreateInput>
, ISfsCrudWithDetailsAppService<TEntityDto, TRequestInput, TCreateInput, TDetailDTO, TDetailRequestInput>
, ISfsGetByNumberAppService<TEntityDto>
where TEntity : class, IEntity<Guid>
where TEntityDto : class, IEntityDto<Guid>, new()
where TRequestInput : SfsRequestInputBase
where TDetail : SfsDetailEntityBase
where TDetailDTO : class, new()
where TImportInput : class, new()
{
protected readonly ISfsRepositoryBase<TEntity> _repository;
/// <summary>
/// 实体名称
/// </summary>
protected readonly string EntityClassName = typeof(TEntity).Name;
protected SfsCrudWithDetailsAppServiceBase(ISfsRepositoryBase<TEntity> repository) : base(repository)
{
_repository = repository;
}
protected IDistributedCache<TEntityDto> Cache => LazyServiceProvider.LazyGetRequiredService<IDistributedCache<TEntityDto>>();
protected IDocumentSettingAppService DocumentSettingAppService => LazyServiceProvider.LazyGetRequiredService<IDocumentSettingAppService>();
protected IExportImportService ExportImportService => LazyServiceProvider.LazyGetRequiredService<IExportImportService>();
protected IHttpContextAccessor HttpContextAccessor => LazyServiceProvider.LazyGetRequiredService<IHttpContextAccessor>();
protected ILocalEventBus LocalEventBus => LazyServiceProvider.LazyGetRequiredService<ILocalEventBus>();
/// <summary>
///
/// </summary>
protected ISettingManager SettingManager => LazyServiceProvider.LazyGetRequiredService<ISettingManager>();
/// <summary>
/// 添加明细列表
/// </summary>
/// <param name="id">实体Id</param>
/// <param name="list">明细列表</param>
[HttpPost("details/")]
public virtual async Task AddDetailListAsync(Guid id, List<TDetailDTO> list)
{
var entity = await _repository.GetAsync(id).ConfigureAwait(false);
Check.NotNull(entity, EntityClassName);
var details = ObjectMapper.Map<List<TDetailDTO>, List<TDetail>>(list);
if (entity is SfsMasterAggregateRootBase<TDetail> masterEntity)
{
masterEntity.AddDetails(details);
}
}
/// <summary>
/// 新增实体
/// </summary>
/// <param name="input">CreateInput</param>
[HttpPost("")]
public override async Task<TEntityDto> CreateAsync(TCreateInput input)
{
await CheckCreatePolicyAsync().ConfigureAwait(continueOnCapturedContext: false);
var entity = input.ToObject<TEntity>();
SetIdForGuids(entity);
TryToSetTenantId(entity);
await Repository.InsertAsync(entity, autoSave: true).ConfigureAwait(continueOnCapturedContext: false);
var dto = entity.ToObject<TEntityDto>();
await Cache.SetItemAsync(dto.Id.ToString(), dto, SfsCacheConst.SeveralMinutes).ConfigureAwait(false);
return dto;
}
/// <summary>
/// 删除实体
/// </summary>
/// <param name="id">实体Id</param>
[HttpDelete("{id}")]
public override async Task DeleteAsync(Guid id)
{
await Repository.DeleteAsync(id).ConfigureAwait(false);
await Cache.DeleteItemAsync(id.ToString()).ConfigureAwait(false);
return;
}
/// <summary>
/// 删除明细
/// </summary>
/// <param name="id">实体Id</param>
/// <param name="detailId">明细Id</param>
/// <returns></returns>
[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<TDetail> masterEntity)
{
masterEntity.RemoveDetail(detailId);
}
}
/// <summary>
/// 导出数据
/// </summary>
[HttpPost("export")]
public virtual async Task<IActionResult> ExportAsync(TRequestInput input)
{
var expression = input.Condition.Filters?.Count > 0
? input.Condition.Filters.ToLambda<TEntity>()
: p => true;
var entities = await _repository.GetPagedListAsync(expression, input.SkipCount, input.MaxResultCount,
input.Sorting, true).ConfigureAwait(false);
var list = ObjectMapper.Map<List<TEntity>, List<TEntityDto>>(entities);
var hasDetails = typeof(TEntity) is SfsMasterAggregateRootBase<TDetail> detailEntity;
return ExportImportService.Export(list, detailsProptyName: hasDetails ? nameof(detailEntity.Details) : null);
}
/// <summary>
/// 按条件获取全部数据列表
/// </summary>
/// <param name="sfsRequestInput">RequestInput</param>
/// <param name="includeDetails">是否包含明细</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpPost("get-all")]
public virtual async Task<List<TEntityDto>> GetAllListByFilterAsync(TRequestInput sfsRequestInput, bool includeDetails = false,
CancellationToken cancellationToken = default)
{
Expression<Func<TEntity, bool>> expression = sfsRequestInput.Condition.Filters?.Count > 0
? sfsRequestInput.Condition.Filters.ToLambda<TEntity>()
: p => true;
return await GetAllListAsync(expression, sfsRequestInput.Sorting, includeDetails, cancellationToken).ConfigureAwait(false);
}
/// <summary>
/// 按Id获取实体
/// </summary>
/// <param name="id">实体Id</param>
/// <returns></returns>
[HttpGet("{id}")]
public override async Task<TEntityDto> GetAsync(Guid id)
{
var dto = await Cache.GetOrAddItemAsync(
id.ToString(),
async () => await base.GetAsync(id).ConfigureAwait(false),
SfsCacheConst.SeveralMinutes).ConfigureAwait(false);
return dto;
}
/// <summary>
/// 按编号获取实体
/// </summary>
/// <param name="number">编号</param>
/// <returns></returns>
[HttpGet("by-number")]
public virtual async Task<TEntityDto> GetByNumberAsync(string number)
{
var entity = (await _repository.GetQueryableAsync().ConfigureAwait(false)).Where("Number=@0", number).FirstOrDefault();
var dto = ObjectMapper.Map<TEntity, TEntityDto>(entity);
return dto;
}
/// <summary>
/// 按条件获取数量
/// request sample
/// {
/// "maxResultCount": 1000,
/// "skipCount": 0,
/// "sorting": "",
/// "condition": { "filters": []}
/// }
/// </summary>
/// <param name="sfsRequestInput">RequestInput</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpPost("count")]
public virtual async Task<long> GetCountByFilterAsync(TRequestInput sfsRequestInput, CancellationToken cancellationToken = default)
{
Expression<Func<TEntity, bool>> expression = sfsRequestInput.Condition.Filters?.Count > 0
? sfsRequestInput.Condition.Filters.ToLambda<TEntity>()
: p => true;
var count = await _repository.GetCountAsync(expression, cancellationToken).ConfigureAwait(false);
return count;
}
/// <summary>
/// 获取明细
/// </summary>
/// <param name="id">实体Id</param>
/// <param name="detailId">明细Id</param>
/// <returns></returns>
[HttpGet("details/{id}")]
public virtual async Task<TDetailDTO> GetDetailAsync(Guid id, Guid detailId)
{
var entity = await _repository.GetAsync(id).ConfigureAwait(false);
Check.NotNull(entity, EntityClassName);
if (entity is SfsMasterAggregateRootBase<TDetail> masterEntity)
{
var detail = masterEntity.GetDetail(detailId);
var dto = ObjectMapper.Map<TDetail, TDetailDTO>(detail);
return dto;
}
return null;
}
/// <summary>
/// 按条件获取明细列表
/// </summary>
/// <param name="id">实体Id</param>
/// <param name="requestInput">明细RequestInput</param>
/// <returns></returns>
[HttpGet("details/")]
public virtual async Task<List<TDetailDTO>> GetDetailListAsync(Guid id, TDetailRequestInput requestInput)
{
var entity = await _repository.GetAsync(id).ConfigureAwait(false);
Check.NotNull(entity, EntityClassName);
if (entity is SfsMasterAggregateRootBase<TDetail> masterEntity)
{
var details = masterEntity.GetDetailList(d => d.MasterID == id).ToList();
var dtos = ObjectMapper.Map<List<TDetail>, List<TDetailDTO>>(details);
return dtos;
}
return null;
}
/// <summary>
/// 屏蔽基类方法
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[NonAction]
public override async Task<PagedResultDto<TEntityDto>> GetListAsync(TRequestInput input)
{
return await base.GetListAsync(input).ConfigureAwait(false);
}
/// <summary>
/// 按条件获取分页列表
/// request sample
/// {
/// "maxResultCount": 1000,
/// "skipCount": 0,
/// "sorting": "",
/// "condition": { "filters": []}
/// }
/// </summary>
/// <param name="sfsRequestInput">RequestInput</param>
/// <param name="includeDetails">是否包含明细</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpPost("list")]
public virtual async Task<PagedResultDto<TEntityDto>> GetPagedListByFilterAsync(TRequestInput sfsRequestInput, bool includeDetails = false,
CancellationToken cancellationToken = default)
{
Expression<Func<TEntity, bool>> expression = sfsRequestInput.Condition.Filters?.Count > 0
? sfsRequestInput.Condition.Filters.ToLambda<TEntity>()
: p => true;
return await GetPagedListAsync(expression, sfsRequestInput.SkipCount, sfsRequestInput.MaxResultCount, sfsRequestInput.Sorting, includeDetails, cancellationToken).ConfigureAwait(false);
}
/// <summary>
/// 按关键字获取分页列表
/// </summary>
/// <param name="keyWord">关键字</param>
/// <param name="skipCount">跳过数</param>
/// <param name="maxResultCount">最大结果数</param>
/// <param name="sorting">排序</param>
/// <param name="includeDetails">是否包含明细</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpPost("search")]
public virtual async Task<PagedResultDto<TEntityDto>> 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);
}
/// <summary>
/// 导入数据
/// </summary>
[HttpPost("import")]
[Consumes("multipart/form-data")]
[UnitOfWork]
public virtual async Task<IActionResult> 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)
{
}
}
/// <summary>
/// 获取导入模板
/// </summary>
[HttpPost("import-template")]
public virtual IActionResult ImportTemplateAsync()
{
return ExportImportService.GetImportTemplate<TImportInput>();
}
/// <summary>
/// 修改实体
/// </summary>
/// <param name="id">实体Id</param>
/// <param name="input">UpdateInput</param>
/// <returns></returns>
[HttpPut("{id}")]
public override async Task<TEntityDto> 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<TEntityDto>();
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);
}
}
/// <summary>
/// 更新明细
/// </summary>
/// <param name="id">实体Id</param>
/// <param name="detailId">明细Id</param>
/// <param name="updateDTO">明细UpdateDto</param>
/// <returns></returns>
[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<TDetailDTO, TDetail>(updateDTO);
if (entity is SfsMasterAggregateRootBase<TDetail> masterEntity)
{
masterEntity.ReplaceDetail(detailId, detail);
}
}
/// <summary>
/// 构造搜索条件表达式
/// </summary>
/// <param name="keyWord">搜索关键字</param>
/// <returns></returns>
protected virtual Expression<Func<TEntity, bool>> BuildSearchExpression(string keyWord)
{
// p => p.Id.ToString().Contains(keyWord);
var expression = typeof(TEntity).GetExpressionByProperty<TEntity>("Number", keyWord);
return expression;
}
protected virtual async Task<string> 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} 单据编号,请联系管理员处理。");
}
}
}
/// <summary>
/// 按表达式条件获取分页列表
/// </summary>
/// <param name="expression"></param>
/// <param name="sorting"></param>
/// <param name="includeDetails"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
protected async Task<List<TEntityDto>> GetAllListAsync(Expression<Func<TEntity, bool>> expression, string sorting, bool includeDetails,
CancellationToken cancellationToken)
{
var entities = await _repository.GetListAsync(expression, sorting, includeDetails, cancellationToken).ConfigureAwait(false);
var dtos = ObjectMapper.Map<List<TEntity>, List<TEntityDto>>(entities);
return dtos;
}
/// <summary>
/// 导入查询实体,可重写
/// </summary>
/// <param name="importInput"></param>
/// <returns></returns>
protected virtual async Task<TEntity> GetEntityAsync(TImportInput importInput)
{
var source = await _repository.GetDbSetAsync().ConfigureAwait(false);
return source.AsQueryable().WhereByKey(importInput)?.FirstOrDefault();
}
/// <summary>
/// 按表达式条件获取分页列表
/// </summary>
/// <param name="expression"></param>
/// <param name="skipCount"></param>
/// <param name="maxResultCount"></param>
/// <param name="sorting"></param>
/// <param name="includeDetails"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
protected async Task<PagedResultDto<TEntityDto>> GetPagedListAsync(Expression<Func<TEntity, bool>> 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<TEntity>, List<TEntityDto>>(entities);
return new PagedResultDto<TEntityDto>(totalCount, dtos);
}
/// <summary>
/// 导入数据具体实现,可重写
/// </summary>
[UnitOfWork]
protected virtual async Task<SfsImportResult> ImportInternalAsync(SfsImportRequestInput requestInput, byte[] inputFileBytes)
{
try
{
var hasDetails = typeof(TEntity).GetInterfaces().Any(o => o.IsGenericType && o.GetGenericTypeDefinition() == typeof(IMasterEntity<>));
var modelList = ExportImportService.Import<TImportInput>(inputFileBytes);
var modelDict = new Dictionary<TImportInput, List<ValidationResult>>();
var entityDict = new Dictionary<TEntity, EntityState>();
foreach (var model in modelList)
{
// DataAnnotations 静态验证
var validationRresults = new List<ValidationResult>();
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 };
}
}
/// <summary>
/// 发布新增事件
/// </summary>
/// <param name="entities"></param>
/// <returns></returns>
private async Task PublishCreatedAsync(List<TEntity> entities)
{
try
{
await LocalEventBus.PublishAsync(new SfsCreatedEntityEventData<List<TEntity>>(entities),false).ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.LogDebug($"{typeof(TEntity).Name} Created Event:{ex.Message}", null);
Console.WriteLine(ex.Source);
throw;
}
}
/// <summary>
/// 用来重写 导入数据时可以加工数据
/// </summary>
/// <param name="dictionary"></param>
/// <returns></returns>
protected virtual async Task<Dictionary<TEntity, EntityState>> ImportProcessingEntityAsync(Dictionary<TEntity, EntityState> dictionary)
{
return dictionary;
}
/// <summary>
/// 导入保存到数据库,可重写
/// </summary>
protected virtual async Task SaveImportAsync(Dictionary<TEntity, EntityState> dict)
{
var entityList = dict.Keys.ToList();
var context = await _repository.GetDbContextAsync().ConfigureAwait(false);
var list = new List<TDetail>();
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<TDetail>)entityDetails)!);
}
}
}
var bulkConfig = new BulkConfig()
{
SetOutputIdentity = true,
PreserveInsertOrder = true
};
await context.BulkInsertOrUpdateAsync(entityList, bulkConfig).ConfigureAwait(false);
await context.BulkInsertAsync(list).ConfigureAwait(false);
}
}
/// <summary>
/// 导入批量验证,可重写
/// </summary>
protected virtual async Task<bool> ValidateImportEntities(Dictionary<TEntity, EntityState> dict)
{
return await Task.FromResult(true).ConfigureAwait(false);
}
/// <summary>
/// 导入单个输入,可重写
/// </summary>
/// <param name="model"></param>
/// <param name="validationRresult"></param>
/// <returns></returns>
protected virtual async Task ValidateImportModelAsync(TImportInput model, List<ValidationResult> validationRresult)
{
await Task.CompletedTask.ConfigureAwait(false);
}
/// <summary>
/// 验证单个实体,可重写
/// </summary>
/// <param name="model"></param>
/// <param name="entity"></param>
/// <param name="validationRresult"></param>
/// <returns></returns>
protected virtual async Task ValidateImportEntityAsync(TImportInput model, TEntity entity, List<ValidationResult> validationRresult)
{
await Task.CompletedTask.ConfigureAwait(false);
}
private async Task ImportValidationAsync(SfsImportRequestInput requestInput, Dictionary<TImportInput, List<ValidationResult>> modelDict, Dictionary<TEntity, EntityState> entityDict, TImportInput model, List<ValidationResult> validationRresults, List<TImportInput> 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<TImportInput, TEntity>(model);
if (entity is SfsMasterAggregateRootBase<TDetail> 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<Guid> creation)
{
creation.CreationTime = DateTime.Now;
creation.CreatorId = CurrentUser.Id;
}
// 清空现有子表
(entity as SfsMasterAggregateRootBase<TDetail>)?.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<TDetail> masterEntity)
{
foreach (var item in detailModels)
{
var detail = ObjectMapper.Map<TImportInput, TDetail>(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<Guid> creation)
{
creation.CreationTime = DateTime.Now;
creation.CreatorId = CurrentUser.Id;
}
}
}
await ValidateImportEntityAsync(model, entity, validationRresults).ConfigureAwait(false);
entityDict.Add(entity, hasEntity ? EntityState.Modified : EntityState.Added);
}
}
}