diff --git a/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Application/AppBase/ZbxBase.cs b/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Application/AppBase/ZbxBase.cs index 524ba2c..a738d9b 100644 --- a/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Application/AppBase/ZbxBase.cs +++ b/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Application/AppBase/ZbxBase.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Linq.Dynamic.Core; using System.Linq.Expressions; @@ -8,8 +9,11 @@ using System.Threading; using System.Threading.Tasks; using AutoMapper; using Faster.Zheng.Winin.AppBase.Filters; +using Faster.Zheng.Winin.Extensions; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using NPOI.SS.UserModel; +using NPOI.XSSF.UserModel; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Abp.Domain.Entities; @@ -17,6 +21,7 @@ using Volo.Abp.Domain.Repositories; using Volo.Abp.EntityFrameworkCore; using static Microsoft.EntityFrameworkCore.DbLoggerCategory; using static OpenIddict.Abstractions.OpenIddictConstants; +using static Volo.Abp.UI.Navigation.DefaultMenuNames.Application; namespace Faster.Zheng.Winin.AppBase; @@ -92,20 +97,7 @@ public class ZbxBase - { - cfg.CreateMap(); - }); - var _mapper = mapperConfig.CreateMapper(); - var source = Expression.Parameter(typeof(TCreateInput), "source"); - _mapFunc = Expression.Lambda>( - Expression.Invoke(Expression.Constant(_mapper.Map)), source) - .Compile(); - - - var tt= _mapper.Map(input); - - var entity = await MapToEntityAsync(input); + var entity = input!.ToObject(); //判断id是否是00000-0000 如果是则赋值 var mainId = (Guid)entity.GetType().GetProperty("Id")?.GetValue(entity)!; @@ -197,9 +189,119 @@ public class ZbxBase /// [HttpPut("api/[controller]/base/update-by-id")] - public override Task UpdateAsync(TKey id, TUpdateInput input) + public override async Task UpdateAsync(TKey id, TUpdateInput input) { - return base.UpdateAsync(id, input); + //return base.UpdateAsync(id, input); + + await CheckUpdatePolicyAsync().ConfigureAwait(continueOnCapturedContext: false); + TEntity entity = await GetEntityByIdAsync(id).ConfigureAwait(continueOnCapturedContext: false); + entity.FromObject(input!); + + #region 给所有字表的 Id和MasterId赋值 否则默认的会是000000-000-....的id 插入时会报错 + + var propertyInfos = entity.GetType().GetProperties(); + foreach (var propertyInfo in propertyInfos) + { + //判断是否是List集合 + if (propertyInfo.Name == "Details" + && propertyInfo.PropertyType.IsGenericType + && propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(List<>)) + { + var listProperty = typeof(TEntity).GetProperty("Details"); + + // 获取 List 的元素类型 + if (listProperty != null) + { + var listItemType = listProperty.PropertyType.GetGenericArguments()[0]; + + // 获取元素类型的 ID 属性 + var detailIdProperty = listItemType.GetProperty("Id"); + var masterIdProperty = listItemType.GetProperty("MasterId"); + + if (detailIdProperty != null) + { + // 获取 List 属性的值 + var list = (IList)listProperty.GetValue(entity); + + // 遍历 List 集合中的每个元素,给 ID 属性赋值 + if (list != null) + { + foreach (var item in list) + { + if ((Guid)detailIdProperty.GetValue(item)! == Guid.Empty) + { + detailIdProperty.SetValue(item, Guid.NewGuid()); + } + } + } + } + + if (masterIdProperty != null) + { + // 获取 List 属性的值 + var list = (IList)listProperty.GetValue(entity); + + // 遍历 List 集合中的每个元素,给 ID 属性赋值 + if (list != null) + { + foreach (var item in list) + { + masterIdProperty.SetValue(item, id); + } + } + } + } + } + } + + #endregion + + await Repository.UpdateAsync(entity, autoSave: true); + + return await MapToGetOutputDtoAsync(entity); + } + + /// + /// 导出Excel + /// + /// + /// + /// + [HttpPost("api/[controller]/base/export-to-excel")] + public void ExportToExcel(IEnumerable data, string filePath) + { + IWorkbook workbook = new XSSFWorkbook(); + ISheet sheet = workbook.CreateSheet("Sheet1"); + + // 获取泛型参数的类型 + var type = typeof(T); + var properties = type.GetProperties(); + + // 创建表头 + IRow headerRow = sheet.CreateRow(0); + for (int i = 0; i < properties.Length; i++) + { + headerRow.CreateCell(i).SetCellValue(properties[i].Name); + } + + // 填充数据行 + int rowIndex = 1; + foreach (var item in data) + { + IRow dataRow = sheet.CreateRow(rowIndex); + for (int i = 0; i < properties.Length; i++) + { + var value = properties[i].GetValue(item); + dataRow.CreateCell(i).SetCellValue(value?.ToString()); + } + rowIndex++; + } + + // 保存Excel文件 + using (FileStream fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write)) + { + workbook.Write(fileStream,true); + } } #endregion diff --git a/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Application/Extensions/ExpressionExtensions.cs b/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Application/Extensions/ExpressionExtensions.cs new file mode 100644 index 0000000..f1a989b --- /dev/null +++ b/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Application/Extensions/ExpressionExtensions.cs @@ -0,0 +1,23 @@ +using System.Linq.Expressions; + +namespace Faster.Zheng.Winin.Extensions; + +public static class ExpressionExtensions +{ + public static string GetMemberName(Expression expression) + { + if (expression is MemberExpression member) + { + return member.Member.Name; + } + else if (expression is MethodCallExpression method) + { + return method.Method.Name; + } + else if (expression is UnaryExpression unary) + { + return GetMemberName(unary); + } + return null; + } +} diff --git a/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Application/Extensions/ObjectExpressionExtensions.cs b/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Application/Extensions/ObjectExpressionExtensions.cs new file mode 100644 index 0000000..f034209 --- /dev/null +++ b/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Application/Extensions/ObjectExpressionExtensions.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Linq.Expressions; +using System.Reflection; + +namespace Faster.Zheng.Winin.Extensions; + +public static class ObjectExpressionExtensions +{ + public static IQueryable WhereByKey(this IQueryable source, TModel model) + { + if (model == null) + { + return null; + } + var modelType = model.GetType(); + var properties = modelType.GetProperties().Where(o => o.GetCustomAttribute() != null).ToList(); + if (properties.Any()) + { + foreach (var property in properties) + { + var propertyName = property.Name; + var propertyValue = property.GetValue(model, null); + source = source.Where($"{propertyName} == @0", propertyValue); + } + return source; + } + return null; + } + + public static List> GroupByKey(this IQueryable source) + { + var properties = typeof(T).GetProperties().Where(o => o.GetCustomAttribute() != null).ToList(); + var names = string.Join(",", properties.Select(o => o.Name)); + return source.AsQueryable().GroupBy($"new ({names})").ToDynamicList>(); + } + + public static Expression> GetExpressionByProperty(this Type type, string propertyName, string propertyValue) + { + var o = Expression.Parameter(type, "p"); + var memberExpression = Expression.Property(o, propertyName); + var body = Expression.Call(typeof(string).GetMethod("Contains", new[] { typeof(string) }), memberExpression); + var predicate = Expression.Lambda>(body, o); + return predicate; + } +} diff --git a/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Application/Extensions/ObjectMapperExtensions.cs b/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Application/Extensions/ObjectMapperExtensions.cs new file mode 100644 index 0000000..8c81737 --- /dev/null +++ b/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Application/Extensions/ObjectMapperExtensions.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using Omu.ValueInjecter; +using Omu.ValueInjecter.Injections; +using Volo.Abp; + +namespace Faster.Zheng.Winin.Extensions; + +/// +/// 对象映射 +/// +public static class ObjectMapperExtensions +{ + /// + /// 从模型更新实体 + /// + public static T FromObject(this T to, object from) + { + try + { + to.InjectFrom(from); + return to; + } + catch (Exception ex) + { + throw new UserFriendlyException($"{from.GetType().FullName}映射到${typeof(T).FullName}时失败:{ex.Message},{ex}"); + } + } + + /// + /// 从实体创建模型 + /// + /// + /// + /// + public static T ToObject(this object from) + { + try + { + if (typeof(T).IsGenericType && typeof(T).IsAssignableTo(typeof(IList)) && from is IList list) + { + var toListType = typeof(T); + var elementType = typeof(T).GetGenericArguments()[0]; + var toList = (IList)Activator.CreateInstance(typeof(T))!; + var fromList = list; + foreach (var item in fromList) + { + toList.Add(Activator.CreateInstance(elementType).InjectFrom(item)); + } + return (T)toList; + } + return (T)Activator.CreateInstance().InjectFrom(from); + } + catch (Exception ex) + { + throw new UserFriendlyException($"{from.GetType().FullName}映射到${typeof(T).FullName}时失败:{ex.Message},{ex}"); + } + } + + private class DeepInjection : LoopInjection + { + protected override bool MatchTypes(Type sourceType, Type targetType) + { + if (sourceType != typeof(string) && + targetType != typeof(string) && + sourceType.IsGenericType && + targetType.IsGenericType && + sourceType.IsAssignableTo(typeof(IEnumerable)) && + sourceType.IsAssignableTo(typeof(IEnumerable)) + ) + { + return true; + } + return base.MatchTypes(sourceType, targetType); + } + + protected override void SetValue(object source, object target, PropertyInfo sp, PropertyInfo tp) + { + if (sp.PropertyType != typeof(string) && + sp.PropertyType != typeof(string) && + sp.PropertyType.IsAssignableTo(typeof(IList)) && + tp.PropertyType.IsAssignableTo(typeof(IList))) + { + var targetGenericType = tp.PropertyType.GetGenericArguments()[0]; + var listType = typeof(List<>).MakeGenericType(targetGenericType); + var addMethod = listType.GetMethod("Add"); + var list = Activator.CreateInstance(listType); + var sourceList = (IList)sp.GetValue(source); + foreach (var item in sourceList) + { + addMethod.Invoke(list, new[] { Activator.CreateInstance(targetGenericType).FromObject(item) }); + } + tp.SetValue(target, list); + return; + } + base.SetValue(source, target, sp, tp); + } + } + + private class DeepInjectionForUpdate : DeepInjection + { + protected override void SetValue(object source, object target, PropertyInfo sp, PropertyInfo tp) + { + //if (tp.GetCustomAttribute() != null) + //{ + // return; + //} + base.SetValue(source, target, sp, tp); + } + } +} diff --git a/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Application/Extensions/StringExtensions.cs b/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Application/Extensions/StringExtensions.cs new file mode 100644 index 0000000..826fa66 --- /dev/null +++ b/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Application/Extensions/StringExtensions.cs @@ -0,0 +1,16 @@ +using System; +using System.Security.Cryptography; +using System.Text; + +namespace Faster.Zheng.Winin.Extensions; + +public static class StringExtensions +{ + public static string Md5(this string input) + { + using (var md5 = MD5.Create()) + { + return BitConverter.ToString(md5.ComputeHash(Encoding.ASCII.GetBytes(input))).Replace("-", ""); + } + } +} diff --git a/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Application/Faster.Zheng.Winin.Application.csproj b/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Application/Faster.Zheng.Winin.Application.csproj index 9fce12f..d1d72a2 100644 --- a/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Application/Faster.Zheng.Winin.Application.csproj +++ b/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Application/Faster.Zheng.Winin.Application.csproj @@ -16,6 +16,8 @@ + + diff --git a/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.EntityFrameworkCore/EntityFrameworkCore/WininDbContext.cs b/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.EntityFrameworkCore/EntityFrameworkCore/WininDbContext.cs index f62328c..95cc1a5 100644 --- a/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.EntityFrameworkCore/EntityFrameworkCore/WininDbContext.cs +++ b/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.EntityFrameworkCore/EntityFrameworkCore/WininDbContext.cs @@ -102,8 +102,10 @@ public class WininDbContext : builder.Entity(b => { b.ToTable(WininConsts.DbTablePrefix + "TestSchools", WininConsts.DbSchema, table => table.HasComment("")); - b.ConfigureByConvention(); - + b.ConfigureByConvention(); + + // ֶҪӼɾ + b.HasMany(q => q.Details).WithOne().HasForeignKey(d => d.MasterId).IsRequired(); /* Configure more properties here */ }); diff --git a/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Web/WininWebAutoMapperProfile.cs b/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Web/WininWebAutoMapperProfile.cs index 2c3485e..d36f0d0 100644 --- a/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Web/WininWebAutoMapperProfile.cs +++ b/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Web/WininWebAutoMapperProfile.cs @@ -5,6 +5,7 @@ using Faster.Zheng.Winin.Web.Pages.AppBusiness.TestSchool.TestStudentDetail.View using Faster.Zheng.Winin.AppBusiness.DemoCar.Dtos; using Faster.Zheng.Winin.Web.Pages.AppBusiness.DemoCar.DemoCar.ViewModels; using AutoMapper; +using Microsoft.AspNetCore.Http.HttpResults; namespace Faster.Zheng.Winin.Web; @@ -21,3 +22,4 @@ public class WininWebAutoMapperProfile : Profile CreateMap(); } } + diff --git a/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Web/WininWebModule.cs b/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Web/WininWebModule.cs index de964c6..6357955 100644 --- a/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Web/WininWebModule.cs +++ b/Code/Be/Faster.Zheng.Winin/src/Faster.Zheng.Winin.Web/WininWebModule.cs @@ -43,6 +43,8 @@ using Microsoft.AspNetCore.Mvc.ApiExplorer; using Volo.Abp.AspNetCore.ExceptionHandling; using Volo.Abp.Settings; using Polly; +using Autofac.Core; +using static Faster.Zheng.Winin.Web.WininWebAutoMapperProfile; namespace Faster.Zheng.Winin.Web;