iotgateway/WalkingTec.Mvvm/WalkingTec.Mvvm.Core/BaseImportVM.cs

1444 lines
60 KiB
C#
Raw Normal View History

2021-12-14 14:10:44 +08:00
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text.Json.Serialization;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using NPOI.HSSF.Util;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using WalkingTec.Mvvm.Core.Extensions;
using WalkingTec.Mvvm.Core.Support.FileHandlers;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// 导入接口
/// </summary>
/// <typeparam name="T">导入模版类</typeparam>
public interface IBaseImport<out T> where T : BaseTemplateVM
{
T Template { get; }
byte[] GenerateTemplate(out string displayName);
void SetParms(Dictionary<string, string> parms);
TemplateErrorListVM ErrorListVM { get; set; }
}
/// <summary>
/// 导入基类Excel导入的类应继承本类
/// </summary>
/// <typeparam name="T">导入模版类</typeparam>
/// <typeparam name="P">导入的Model类</typeparam>
public class BaseImportVM<T, P> : BaseVM, IBaseImport<T>
where T : BaseTemplateVM, new()
where P : TopBasePoco, new()
{
#region
/// <summary>
/// 上传文件的Id方便导入等操作中进行绑定这类操作需要上传文件但不需要记录在数据库中所以Model层中没有文件Id的字段
/// </summary>
[Display(Name = "UploadFile")]
public string UploadFileId { get; set; }
/// <summary>
/// 下载模板显示名称
/// </summary>
[JsonIgnore]
public string FileDisplayName { get; set; }
/// <summary>
/// 错误列表
/// </summary>
[JsonIgnore]
public TemplateErrorListVM ErrorListVM { get; set; }
/// <summary>
/// 是否验证模板类型当其他系统模板导入到某模块时可设置为False
/// </summary>
[JsonIgnore]
public bool ValidityTemplateType { get; set; }
/// <summary>
/// 下载模版页面的参数
/// </summary>
[JsonIgnore]
public Dictionary<string, string> Parms { get; set; }
protected List<T> TemplateData;
/// <summary>
/// 要导入的Model列表
/// </summary>
[JsonIgnore]
public List<P> EntityList { get; set; }
/// <summary>
/// 模版
/// </summary>
[JsonIgnore]
public T Template { get; set; }
/// <summary>
/// Model数据是否已被赋值
/// </summary>
protected bool isEntityListSet = false;
/// <summary>
/// 声明XSSF
/// </summary>
protected XSSFWorkbook xssfworkbook;
/// <summary>
/// 唯一性验证
/// </summary>
protected DuplicatedInfo<P> finalInfo;
/// <summary>
/// 是否存在主子表
/// </summary>
protected bool HasSubTable { get; set; }
/// <summary>
/// 是否在sqlserver时使用bulk导入
/// </summary>
public bool UseBulkSave { get; set; }
/// <summary>
/// 是否覆盖已有数据
/// </summary>
public bool IsOverWriteExistData { get; set; } = true;
#endregion
#region
public BaseImportVM()
{
ErrorListVM = new TemplateErrorListVM();
ValidityTemplateType = true;
Template = new T();
}
#endregion
#region excel
/// <summary>
/// 生成模版
/// </summary>
/// <param name="displayName">模版文件名</param>
/// <returns>生成的模版</returns>
public virtual byte[] GenerateTemplate(out string displayName)
{
return Template.GenerateTemplate(out displayName);
}
#endregion
#region
/// <summary>
/// 设置模版参数
/// </summary>
/// <param name="parms">参数</param>
public void SetParms(Dictionary<string, string> parms)
{
Template.Parms = parms;
}
#endregion
#region
/// <summary>
/// 设置数据唯一性验证,子类中如果需要数据唯一性验证,应重写此方法
/// </summary>
/// <returns>唯一性属性</returns>
public virtual DuplicatedInfo<P> SetDuplicatedCheck()
{
return null;
}
/// <summary>
/// 获取上传的结果值
/// </summary>
public virtual void SetEntityList()
{
if (!isEntityListSet)
{
EntityList = new List<P>();
//初始化上传的模板数据
SetTemplateData();
//如果模板中有错误,直接返回
if (ErrorListVM.EntityList.Count > 0)
{
return;
}
//对EntityList赋值
SetEntityData();
//设置标识为初始化
isEntityListSet = true;
}
}
/// <summary>
/// 获取上传模板中填写的数据,包含了对模板正确性的验证
/// </summary>
public virtual void SetTemplateData()
{
if (TemplateData != null && TemplateData.Count > 0)
{
return;
}
try
{
TemplateData = new List<T>();
xssfworkbook = new XSSFWorkbook();
//【CHECK】上传附件的ID为空
if (UploadFileId == null)
{
ErrorListVM.EntityList.Add(new ErrorMessage { Message = CoreProgram._localizer?["Sys.PleaseUploadTemplate"] });
return;
}
Models.IWtmFile file = null;
if (Wtm.ServiceProvider != null)
{
var fp = Wtm.ServiceProvider.GetRequiredService<WtmFileProvider>();
file = fp.GetFile(UploadFileId, true, DC);
}
if (file == null)
{
ErrorListVM.EntityList.Add(new ErrorMessage { Message = CoreProgram._localizer?["Sys.WrongTemplate"] });
return;
}
xssfworkbook = new XSSFWorkbook(file.DataStream);
file.DataStream.Dispose();
Template.InitExcelData();
Template.InitCustomFormat();
//【CHECK】判断是否上传的是正确的模板数据
string TemplateHiddenName = xssfworkbook.GetSheetAt(1).GetRow(0).Cells[2].ToString();
if (ValidityTemplateType && !TemplateHiddenName.Equals(typeof(T).Name))
{
ErrorListVM.EntityList.Add(new ErrorMessage { Message = CoreProgram._localizer?["Sys.WrongTemplate"] });
return;
}
//获取数据的Sheet页信息
ISheet sheet = xssfworkbook.GetSheetAt(0);
sheet.ForceFormulaRecalculation = true;
XSSFFormulaEvaluator XE = new XSSFFormulaEvaluator(xssfworkbook);
IEnumerator rows = sheet.GetRowEnumerator();
var cells = sheet.GetRow(0).Cells;
//获取模板中所有字段的属性
List<ExcelPropety> ListTemplateProptetys = new List<ExcelPropety>();
var ListPropetys = Template.GetType().GetFields().Where(x => x.FieldType == typeof(ExcelPropety)).ToList();
for (int i = 0; i < ListPropetys.Count(); i++)
{
ExcelPropety ep = (ExcelPropety)ListPropetys[i].GetValue(Template);
ListTemplateProptetys.Add(ep);
}
//【CHECK】验证模板的列数是否正确
var dynamicColumn = ListTemplateProptetys.Where(x => x.DataType == ColumnDataType.Dynamic).FirstOrDefault();
int columnCount = dynamicColumn == null ? ListTemplateProptetys.Count : (ListTemplateProptetys.Count + dynamicColumn.DynamicColumns.Count - 1);
if (columnCount != cells.Count)
{
ErrorListVM.EntityList.Add(new ErrorMessage { Message = CoreProgram._localizer?["Sys.WrongTemplate"] });
return;
}
//【CHECK】判断字段是否根据顺序能一对一相对应。 //是否可以去除?
int pIndex = 0;
HasSubTable = false;
for (int i = 0; i < cells.Count; i++)
{
//是否有子表
HasSubTable = ListTemplateProptetys[pIndex].SubTableType != null ? true : HasSubTable;
//if (ListTemplateProptetys[pIndex].DataType != ColumnDataType.Dynamic)
//{
// if (cells[i].ToString().Trim('*') != ListTemplateProptetys[pIndex].ColumnName)
// {
// ErrorListVM.EntityList.Add(new ErrorMessage { Message = CoreProgram._localizer?["Sys.WrongTemplate"] });
// return;
// }
// pIndex++;
//}
//else
//{
// var listDynamicColumns = ListTemplateProptetys[i].DynamicColumns;
// int dcCount = listDynamicColumns.Count;
// for (int dclIndex = 0; dclIndex < dcCount; dclIndex++)
// {
// if (cells[i].ToString().Trim('*') != listDynamicColumns[dclIndex].ColumnName)
// {
// ErrorListVM.EntityList.Add(new ErrorMessage { Message = CoreProgram._localizer?["Sys.WrongTemplate"] });
// break;
// }
// i = i + 1;
// }
// i = i - 1;
pIndex++;
//}
}
//如果有子表,则设置主表字段非必填
if (HasSubTable)
{
for (int i = 0; i < cells.Count; i++)
{
ListTemplateProptetys[i].IsNullAble = ListTemplateProptetys[i].SubTableType == null ? true : ListTemplateProptetys[i].IsNullAble;
}
}
//向TemplateData中赋值
int rowIndex = 2;
rows.MoveNext();
while (rows.MoveNext())
{
XSSFRow row = (XSSFRow)rows.Current;
if (IsEmptyRow(row, columnCount))
{
return;
}
T result = new T();
pIndex = 0;
for (int i = 0; i < columnCount; i++)
{
//获取列的值
string value = row.GetCell(i, MissingCellPolicy.CREATE_NULL_AS_BLANK).ToString();
ExcelPropety excelPropety = CopyExcelPropety(ListTemplateProptetys[pIndex]);
if (excelPropety.DataType == ColumnDataType.Text)
{
ICell cell = row.GetCell(i);
value = GetCellFormulaValue(XE, cell, value);
}
if (excelPropety.DataType == ColumnDataType.Dynamic)
{
int dynamicColCount = excelPropety.DynamicColumns.Count();
for (int dynamicColIndex = 0; dynamicColIndex < dynamicColCount; dynamicColIndex++)
{
excelPropety.DynamicColumns[dynamicColIndex].ValueValidity(row.GetCell(i + dynamicColIndex, MissingCellPolicy.CREATE_NULL_AS_BLANK).ToString(), ErrorListVM.EntityList, rowIndex);
}
i = i + dynamicColCount - 1;
}
else
{
excelPropety.ValueValidity(value, ErrorListVM.EntityList, rowIndex);
}
//如果没有错误,进行赋值
if (ErrorListVM.EntityList.Count == 0)
{
var pts = ListPropetys[pIndex];
pts.SetValue(result, excelPropety);
}
pIndex++;
}
result.ExcelIndex = rowIndex;
TemplateData.Add(result);
rowIndex++;
}
return;
}
catch
{
ErrorListVM.EntityList.Add(new ErrorMessage { Message = CoreProgram._localizer?["Sys.WrongTemplate"] });
}
}
#region
public string GetCellFormulaValue(XSSFFormulaEvaluator XE, ICell cell, string Value)
{
if (!string.IsNullOrEmpty(Value) && Value.IndexOf("=") == 0)
{
try
{
string Formula = Value.Substring(1);
cell.SetCellFormula(Formula);
XE.EvaluateFormulaCell(cell);
Value = cell.NumericCellValue.ToString();
}
catch (Exception)
{
}
}
return Value;
}
#endregion
/// <summary>
/// 根据模板中的数据,填写导入类的集合中
/// </summary>
public virtual void SetEntityData()
{
//反射出类中所有属性字段 P是Model层定义的类
var pros = typeof(P).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
//反射出模板类中的所有属性字段 T是模板类ExcelProperty 是自定义的Excel属性类
List<FieldInfo> ListExcelFields = typeof(T).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).Where(x => x.FieldType == typeof(ExcelPropety)).ToList();
//循环Excel中的数据
foreach (var item in TemplateData)
{
int rowIndex = 2;
bool isMainData = false;
//主表信息
Dictionary<string, ExcelPropety> ParentEntity = new Dictionary<string, ExcelPropety>();
string ParentEntityValues = string.Empty;
//子表信息
Dictionary<Type, List<FieldInfo>> ChildrenEntity = new Dictionary<Type, List<FieldInfo>>();
Dictionary<Type, string> ChildrenEntityDic = new Dictionary<Type, string>();
//循环TemplateVM中定义的所有的列区分出主子表
foreach (var ExcelField in ListExcelFields)
{
//获取本列的ExcelProperty的值
if (typeof(T).GetField(ExcelField.Name).GetValue(item) is ExcelPropety ep)
{
//如果是子表的字段
if (ep.SubTableType != null)
{
//保存子表字段信息稍后处理
if (!ChildrenEntity.ContainsKey(ep.SubTableType))
{
ChildrenEntity[ep.SubTableType] = new List<FieldInfo>();
}
ChildrenEntity[ep.SubTableType].Add(ExcelField);
}
else
{
//保存子表字段信息稍后处理
ParentEntity.Add(ep.FieldName, ep);
ParentEntityValues += ep.Value;
}
}
}
//子表信息是否为空
foreach (var sub in ChildrenEntity)
{
string subVal = string.Empty;
foreach (var field in sub.Value)
{
ExcelPropety ep = typeof(T).GetField(field.Name).GetValue(item) as ExcelPropety;
subVal += ep.Value;
}
ChildrenEntityDic.Add(sub.Key, subVal);
}
P entity = null;
//说明主表信息为空
if (string.IsNullOrEmpty(ParentEntityValues))
{
entity = EntityList.LastOrDefault();
}
else
{
//初始化一个新的Entity
entity = new P();
isMainData = true;
//给主表赋值
foreach (var mep in ParentEntity)
{
SetEntityFieldValue(entity, mep.Value, rowIndex, mep.Key, item);
}
}
//给子表赋值
foreach (var sub in ChildrenEntity)
{
//循环Entity的所有属性找到List<SubTableType>类型的字段
foreach (var pro in pros)
{
if (pro.PropertyType.IsGenericType)
{
var gtype = pro.PropertyType.GetGenericArguments()[0];
if (gtype == sub.Key)
{
//子表
var subList = entity.GetType().GetSingleProperty(pro.Name).GetValue(entity);
string fk = DC.GetFKName<P>(pro.Name);
//如果子表不为空
if (!string.IsNullOrEmpty(ChildrenEntityDic.Where(x => x.Key == sub.Key).FirstOrDefault().Value))
{
IList list = null;
if (subList == null)
{
//初始化List<SubTableType>
list = typeof(List<>).MakeGenericType(gtype).GetConstructor(Type.EmptyTypes).Invoke(null) as IList;
}
else
{
list = subList as IList;
}
//初始化一个SubTableType
var SubTypeEntity = gtype.GetConstructor(System.Type.EmptyTypes).Invoke(null);
//给SubTableType中和本ExcelProperty同名的字段赋值
foreach (var field in sub.Value)
{
ExcelPropety ep = typeof(T).GetField(field.Name).GetValue(item) as ExcelPropety;
SetEntityFieldValue(SubTypeEntity, ep, rowIndex, ep.FieldName, item);
}
if (string.IsNullOrEmpty(fk) == false)
{
PropertyHelper.SetPropertyValue(SubTypeEntity, fk, entity.GetID());
}
if (typeof(IBasePoco).IsAssignableFrom(SubTypeEntity.GetType()))
{
(SubTypeEntity as IBasePoco).CreateTime = DateTime.Now;
(SubTypeEntity as IBasePoco).CreateBy = LoginUserInfo?.ITCode;
}
//var context = new ValidationContext(SubTypeEntity);
//var validationResults = new List<ValidationResult>();
//TryValidateObject(SubTypeEntity, context, validationResults);
//if (validationResults.Count == 0)
//{
//将付好值得SubTableType实例添加到List中
list.Add(SubTypeEntity);
PropertyHelper.SetPropertyValue(entity, pro.Name, list);
//}
//else
//{
// ErrorListVM.EntityList.Add(new ErrorMessage { Message = validationResults.FirstOrDefault()?.ErrorMessage ?? "Error", ExcelIndex = item.ExcelIndex });
// break;
//}
}
break;
}
}
}
}
entity.ExcelIndex = item.ExcelIndex;
if (isMainData)
{
EntityList.Add(entity);
}
}
}
/// <summary>
/// 进行上传中的错误验证
/// </summary>
public virtual void SetValidateCheck()
{
//找到对应的BaseCRUDVM并初始化
var vms = this.GetType().Assembly.GetExportedTypes().Where(x => x.IsSubclassOf(typeof(BaseCRUDVM<P>))).ToList();
var vmtype = vms.Where(x => x.Name.ToLower() == typeof(P).Name.ToLower() + "vm").FirstOrDefault();
if (vmtype == null)
{
vmtype = vms.FirstOrDefault();
}
IBaseCRUDVM<P> vm = null;
DuplicatedInfo<P> dinfo = null;
if (vmtype != null)
{
vm = vmtype.GetConstructor(System.Type.EmptyTypes).Invoke(null) as IBaseCRUDVM<P>;
vm.CopyContext(this);
dinfo = (vm as dynamic).SetDuplicatedCheck();
}
var cinfo = this.SetDuplicatedCheck();
finalInfo = new DuplicatedInfo<P>
{
Groups = new List<DuplicatedGroup<P>>()
};
if (cinfo != null)
{
foreach (var item in cinfo?.Groups)
{
finalInfo.Groups.Add(item);
}
}
else if (dinfo != null)
{
foreach (var item in dinfo?.Groups)
{
finalInfo.Groups.Add(item);
}
}
//调用controller方法验证model
//var vmethod = Controller?.GetType().GetMethod("RedoValidation");
foreach (var entity in EntityList)
{
//try
//{
// vmethod.Invoke(Controller, new object[] { entity });
//}
//catch { }
if (vm != null)
{
vm.SetEntity(entity);
vm.ByPassBaseValidation = true;
vm.Validate();
var basevm = vm as BaseVM;
if (basevm?.MSD?.Count > 0)
{
foreach (var key in basevm.MSD.Keys)
{
foreach (var error in basevm.MSD[key])
{
ErrorListVM.EntityList.Add(new ErrorMessage { Message = error.ErrorMessage, Index = entity.ExcelIndex });
}
}
}
}
(vm as BaseVM)?.MSD.Clear();
//在本地EntityList中验证是否有重复
ValidateDuplicateData(finalInfo, entity);
}
}
protected void SetEntityFieldValue(object entity, ExcelPropety ep, int rowIndex, string fieldName, T templateVM)
{
if (ep.FormatData != null)
{
ProcessResult processResult = ep.FormatData(ep.Value, templateVM);
if (processResult != null)
{
//未添加任何处理结果
if (processResult.EntityValues.Count == 0)
{
PropertyHelper.SetPropertyValue(entity, fieldName, ep.Value, stringBasedValue: true);
}
//字段为一对一
if (processResult.EntityValues.Count == 1)
{
ep.Value = processResult.EntityValues[0].FieldValue;
if (!string.IsNullOrEmpty(processResult.EntityValues[0].ErrorMsg))
{
ErrorListVM.EntityList.Add(new ErrorMessage { Message = processResult.EntityValues[0].ErrorMsg, ExcelIndex = rowIndex, Index = rowIndex });
}
PropertyHelper.SetPropertyValue(entity, fieldName, ep.Value, stringBasedValue: true);
}
//字段为一对多
if (processResult.EntityValues.Count > 1)
{
foreach (var entityValue in processResult.EntityValues)
{
if (!string.IsNullOrEmpty(entityValue.ErrorMsg))
{
ErrorListVM.EntityList.Add(new ErrorMessage { Message = entityValue.ErrorMsg, ExcelIndex = rowIndex, Index = rowIndex });
}
PropertyHelper.SetPropertyValue(entity, entityValue.FieldName, entityValue.FieldValue, stringBasedValue: true);
}
}
}
}
else if (ep.FormatSingleData != null)
{
ep.FormatSingleData(ep.Value, templateVM, out string singleEntityValue, out string errorMsg);
if (!string.IsNullOrEmpty(errorMsg))
{
ErrorListVM.EntityList.Add(new ErrorMessage { Message = errorMsg, ExcelIndex = rowIndex, Index = rowIndex });
}
PropertyHelper.SetPropertyValue(entity, fieldName, singleEntityValue, stringBasedValue: true);
}
else
{
PropertyHelper.SetPropertyValue(entity, fieldName, ep.Value, stringBasedValue: true);
}
}
protected bool IsUpdateRecordDuplicated(DuplicatedInfo<P> checkCondition, P entity)
{
if (checkCondition != null && checkCondition.Groups.Count > 0)
{
//生成基础Query
var baseExp = EntityList.AsQueryable();
var modelType = typeof(P);
ParameterExpression para = Expression.Parameter(modelType, "tm");
//循环所有重复字段组
foreach (var group in checkCondition.Groups)
{
List<Expression> conditions = new List<Expression>();
//生成一个表达式,类似于 x=>x.Id != id这是为了当修改数据时验证重复性的时候排除当前正在修改的数据
var idproperty = modelType.GetSingleProperty("ID");
MemberExpression idLeft = Expression.Property(para, idproperty);
ConstantExpression idRight = Expression.Constant(entity.GetID());
BinaryExpression idNotEqual = Expression.NotEqual(idLeft, idRight);
conditions.Add(idNotEqual);
List<PropertyInfo> props = new List<PropertyInfo>();
//在每个组中循环所有字段
foreach (var field in group.Fields)
{
Expression exp = field.GetExpression(entity, para);
if (exp != null)
{
conditions.Add(exp);
}
//将字段名保存,为后面生成错误信息作准备
props.AddRange(field.GetProperties());
}
int count = 0;
if (conditions.Count > 1)
{
//循环添加条件并生成Where语句
Expression conExp = conditions[0];
for (int i = 1; i < conditions.Count; i++)
{
conExp = Expression.And(conExp, conditions[i]);
}
MethodCallExpression whereCallExpression = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { modelType },
baseExp.Expression,
Expression.Lambda<Func<P, bool>>(conExp, new ParameterExpression[] { para }));
var result = baseExp.Provider.CreateQuery(whereCallExpression);
foreach (var res in result)
{
count++;
}
}
if (count > 0)
{
return true;
}
}
}
return false;
}
protected void ValidateDuplicateData(DuplicatedInfo<P> checkCondition, P entity)
{
if (checkCondition != null && checkCondition.Groups.Count > 0)
{
//生成基础Query
var baseExp = EntityList.AsQueryable();
var modelType = typeof(P);
ParameterExpression para = Expression.Parameter(modelType, "tm");
//循环所有重复字段组
foreach (var group in checkCondition.Groups)
{
List<Expression> conditions = new List<Expression>();
//生成一个表达式,类似于 x=>x.Id != id这是为了当修改数据时验证重复性的时候排除当前正在修改的数据
var idproperty = modelType.GetSingleProperty("ExcelIndex");
MemberExpression idLeft = Expression.Property(para, idproperty);
ConstantExpression idRight = Expression.Constant(entity.ExcelIndex);
BinaryExpression idNotEqual = Expression.NotEqual(idLeft, idRight);
conditions.Add(idNotEqual);
List<PropertyInfo> props = new List<PropertyInfo>();
//在每个组中循环所有字段
foreach (var field in group.Fields)
{
Expression exp = field.GetExpression(entity, para);
if (exp != null)
{
conditions.Add(exp);
}
//将字段名保存,为后面生成错误信息作准备
props.AddRange(field.GetProperties());
}
int count = 0;
if (conditions.Count > 1)
{
//循环添加条件并生成Where语句
Expression whereCallExpression = baseExp.Expression;
for (int i = 0; i < conditions.Count; i++)
{
whereCallExpression = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { modelType },
whereCallExpression,
Expression.Lambda<Func<P, bool>>(conditions[i], new ParameterExpression[] { para }));
}
var result = baseExp.Provider.CreateQuery(whereCallExpression);
foreach (var res in result)
{
count++;
}
}
if (count > 0)
{
//循环拼接所有字段名
string AllName = "";
foreach (var prop in props)
{
string name = PropertyHelper.GetPropertyDisplayName(prop);
AllName += name + ",";
}
if (AllName.EndsWith(","))
{
AllName = AllName.Remove(AllName.Length - 1);
}
//如果只有一个字段重复,则拼接形成 xxx字段重复 这种提示
if (props.Count == 1)
{
ErrorListVM.EntityList.Add(new ErrorMessage { Message = CoreProgram._localizer?["Sys.DuplicateError", AllName], Index = entity.ExcelIndex });
}
//如果多个字段重复,则拼接形成 xxyyzz组合字段重复 这种提示
else if (props.Count > 1)
{
ErrorListVM.EntityList.Add(new ErrorMessage { Message = CoreProgram._localizer?["Sys.DuplicateGroupError", AllName], Index = entity.ExcelIndex });
}
}
}
}
}
private void TryValidateObject(object model, ValidationContext context, ICollection<ValidationResult> results)
{
var modelType = model.GetType();
foreach (var p in modelType.GetProperties())
{
var propertyValue = p.GetValue(model);
TryValidateProperty(propertyValue, context, results, p);
}
}
private void TryValidateProperty(object value, ValidationContext context, ICollection<ValidationResult> results, PropertyInfo propertyInfo = null)
{
var modelType = context.ObjectType;
if (propertyInfo == null)
{
propertyInfo = modelType.GetProperty(context.MemberName!);
}
if (propertyInfo != null)
{
var rules = propertyInfo.GetCustomAttributes(true).Where(i => i.GetType().BaseType == typeof(ValidationAttribute)).Cast<ValidationAttribute>();
var displayName = propertyInfo.GetPropertyDisplayName();
var memberName = propertyInfo.Name;
foreach (var rule in rules)
{
if (!rule.IsValid(value))
{
string errorMessage = "Error";
if (!string.IsNullOrEmpty(rule.ErrorMessage))
{
if (rule is RangeAttribute range)
{
if (range.Minimum != null && range.Maximum != null)
{
errorMessage = Wtm.Localizer[rule.ErrorMessage, displayName, range.Minimum, range.Maximum];
}
else if (range.Minimum != null)
{
errorMessage = Wtm.Localizer[rule.ErrorMessage, displayName, range.Minimum];
}
else if (range.Maximum != null)
{
errorMessage = Wtm.Localizer[rule.ErrorMessage, displayName, range.Maximum];
}
}
else if (rule is StringLengthAttribute sl)
{
if (sl.MaximumLength > 0 && sl.MinimumLength > 0)
{
errorMessage = Wtm.Localizer[rule.ErrorMessage, displayName, sl.MinimumLength, sl.MaximumLength];
}
else if (sl.MinimumLength > 0)
{
errorMessage = Wtm.Localizer[rule.ErrorMessage, displayName, sl.MinimumLength];
}
else if (sl.MaximumLength > 0)
{
errorMessage = Wtm.Localizer[rule.ErrorMessage, displayName, sl.MaximumLength];
}
}
else
{
errorMessage = Wtm.Localizer[rule.ErrorMessage, displayName];
}
}
results.Add(new ValidationResult(errorMessage, new string[] { memberName }));
}
}
}
}
/// <summary>
/// 保存指定表中的数据
/// </summary>
/// <returns>成功返回True失败返回False</returns>
public virtual bool BatchSaveData()
{
//删除不必要的附件
if (DeletedFileIds != null && DeletedFileIds.Count > 0 && Wtm.ServiceProvider != null)
{
var fp = Wtm.ServiceProvider.GetRequiredService<WtmFileProvider>();
foreach (var item in DeletedFileIds)
{
fp.DeleteFile(item.ToString(), DC.ReCreate());
}
}
//进行赋值
SetEntityList();
foreach (var entity in EntityList)
{
var context = new ValidationContext(entity);
var validationResults = new List<ValidationResult>();
TryValidateObject(entity, context, validationResults);
if (validationResults.Count > 0)
{
ErrorListVM.EntityList.Add(new ErrorMessage { Message = validationResults.FirstOrDefault()?.ErrorMessage ?? "Error", ExcelIndex = entity.ExcelIndex, Index = entity.ExcelIndex });
}
}
if (ErrorListVM.EntityList.Count > 0)
{
DoReInit();
return false;
}
//执行验证
SetValidateCheck();
if (ErrorListVM.EntityList.Count > 0)
{
DoReInit();
return false;
}
//循环数据列表
List<P> ListAdd = new List<P>();
foreach (var item in EntityList)
{
//根据唯一性的设定查找数据库中是否有同样的数据
P exist = IsDuplicateData(item, finalInfo);
//如果设置了覆盖功能
if (IsOverWriteExistData)
{
if (exist != null)
{
//如果有重复数据,则进行修改
var tempPros = typeof(T).GetFields();
foreach (var pro in tempPros)
{
var excelProp = Template.GetType().GetField(pro.Name).GetValue(Template) as ExcelPropety;
var proToSet = typeof(P).GetSingleProperty(excelProp.FieldName);
if (proToSet != null)
{
var val = proToSet.GetValue(item);
PropertyHelper.SetPropertyValue(exist, excelProp.FieldName, val, stringBasedValue: true);
try
{
DC.UpdateProperty(exist, proToSet.Name);
}
catch { }
}
}
if (tempPros.Where(x => x.Name == "UpdateTime").SingleOrDefault() == null)
{
if (typeof(IBasePoco).IsAssignableFrom(exist.GetType()))
{
(exist as IBasePoco).UpdateTime = DateTime.Now;
DC.UpdateProperty(exist, "UpdateTime");
}
}
if (tempPros.Where(x => x.Name == "UpdateBy").SingleOrDefault() == null)
{
if (typeof(IBasePoco).IsAssignableFrom(exist.GetType()))
{
(exist as IBasePoco).UpdateBy = LoginUserInfo.ITCode;
DC.UpdateProperty(exist, "UpdateBy");
}
}
exist.ExcelIndex = item.ExcelIndex;
//DC.UpdateEntity(exist);
continue;
}
else
{
if (typeof(IPersistPoco).IsAssignableFrom(item.GetType()))
{
(item as IPersistPoco).IsValid = true;
}
}
}
else
{
if (exist == null)
{
if (typeof(IPersistPoco).IsAssignableFrom(item.GetType()))
{
(item as IPersistPoco).IsValid = true;
}
}
}
//进行添加操作
if (typeof(IBasePoco).IsAssignableFrom(item.GetType()))
{
(item as IBasePoco).CreateTime = DateTime.Now;
(item as IBasePoco).CreateBy = LoginUserInfo?.ITCode;
}
//如果是SqlServer数据库而且没有主子表功能进行Bulk插入
if (ConfigInfo.Connections.Where(x => x.Key == (CurrentCS ?? "default")).FirstOrDefault().DbType == DBTypeEnum.SqlServer && !HasSubTable && UseBulkSave == true)
{
ListAdd.Add(item);
}
else
{
DC.Set<P>().Add(item);
}
}
if (ErrorListVM.EntityList.Count > 0)
{
DoReInit();
return false;
}
//如果没有错误,更新数据库
if (EntityList.Count > 0)
{
try
{
DC.SaveChanges();
if (ListAdd.Count > 0)
{
BulkInsert<P>(DC, DC.GetTableName<P>(), ListAdd);
}
}
catch (Exception e)
{
SetExceptionMessage(e, null);
DoReInit();
return false;
}
}
if (string.IsNullOrEmpty(UploadFileId) == false && Wtm.ServiceProvider != null)
{
var fp = Wtm.ServiceProvider.GetRequiredService<WtmFileProvider>();
fp.DeleteFile(UploadFileId, DC.ReCreate());
}
return true;
}
/// <summary>
/// 批量插入数据库操作支持SqlServer
/// </summary>
/// <typeparam name="K"></typeparam>
/// <param name="dc">data context</param>
/// <param name="tableName"></param>
/// <param name="list"></param>
protected static void BulkInsert<K>(IDataContext dc, string tableName, IList<K> list)
{
using (var bulkCopy = new SqlBulkCopy(dc.CSName))
{
bulkCopy.BatchSize = list.Count;
bulkCopy.DestinationTableName = tableName;
var table = new DataTable();
var props = typeof(K).GetAllProperties().Distinct(x => x.Name);
//生成Table的列
foreach (var propertyInfo in props)
{
var notmapped = propertyInfo.GetCustomAttribute<NotMappedAttribute>();
var notobject = propertyInfo.PropertyType.Namespace.Equals("System") || propertyInfo.PropertyType.IsEnumOrNullableEnum();
if (notmapped == null && notobject)
{
string Name = dc.GetFieldName<K>(propertyInfo.Name);
bulkCopy.ColumnMappings.Add(Name, Name);
table.Columns.Add(Name, Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType);
}
}
//给Table赋值
var values = new object[table.Columns.Count];
foreach (var item in list)
{
var Index = 0;
foreach (var propertyInfo in props)
{
var notmapped = propertyInfo.GetCustomAttribute<NotMappedAttribute>();
var notobject = propertyInfo.PropertyType.Namespace.Equals("System") || propertyInfo.PropertyType.IsEnumOrNullableEnum();
if (notmapped == null && notobject)
{
values[Index] = propertyInfo.GetValue(item);
Index++;
}
}
table.Rows.Add(values);
}
//检测是否有继承字段,如果存在,进行赋值
string Discriminator = dc.GetFieldName<K>("Discriminator");
if (!string.IsNullOrEmpty(Discriminator))
{
bulkCopy.ColumnMappings.Add("Discriminator", "Discriminator");
table.Columns.Add("Discriminator", typeof(string));
for (int i = 0; i < table.Rows.Count; i++)
{
table.Rows[i]["Discriminator"] = typeof(K).Name;
}
}
bulkCopy.WriteToServer(table);
}
}
#endregion
#region
/// <summary>
/// 验证Excel中某行是否为空行
/// </summary>
/// <param name="row">行数</param>
/// <param name="colCount">列数</param>
/// <returns>True代表空行False代表非空行</returns>
private bool IsEmptyRow(XSSFRow row, int colCount)
{
bool result = true;
for (int i = 0; i < colCount; i++)
{
string value = row.GetCell(i, MissingCellPolicy.CREATE_NULL_AS_BLANK).ToString();
if (!string.IsNullOrEmpty(value))
{
result = false;
break;
}
}
return result;
}
#endregion
#region Excel属性
/// <summary>
/// 复制Excel属性
/// </summary>
/// <param name="excelPropety">单元格属性</param>
/// <returns>复制后的单元格</returns>
private ExcelPropety CopyExcelPropety(ExcelPropety excelPropety)
{
ExcelPropety ep = new ExcelPropety
{
BackgroudColor = excelPropety.BackgroudColor,
ColumnName = excelPropety.ColumnName,
DataType = excelPropety.DataType,
ResourceType = excelPropety.ResourceType,
IsNullAble = excelPropety.IsNullAble,
ListItems = excelPropety.ListItems,
MaxValuseOrLength = excelPropety.MaxValuseOrLength,
MinValueOrLength = excelPropety.MinValueOrLength,
Value = excelPropety.Value,
SubTableType = excelPropety.SubTableType,
CharCount = excelPropety.CharCount,
ReadOnly = excelPropety.ReadOnly,
FormatData = excelPropety.FormatData,
FormatSingleData = excelPropety.FormatSingleData,
FieldName = excelPropety.FieldName
};
List<ExcelPropety> li = new List<ExcelPropety>();
foreach (var item in excelPropety.DynamicColumns)
{
li.Add(CopyExcelPropety(item));
}
ep.DynamicColumns = li;
return ep;
}
#endregion
#region
/// <summary>
/// 设置错误信息
/// </summary>
/// <param name="e">异常</param>
/// <param name="id">数据Id</param>
protected void SetExceptionMessage(Exception e, long? id)
{
//检查是否为数据库操作错误
if (e is DbUpdateException)
{
var de = e as DbUpdateException;
if (de.Entries != null)
{
if (de.Entries.Count == 0)
{
ErrorListVM.EntityList.Add(new ErrorMessage { Index = 0, Message = e.Message + e.InnerException?.Message });
}
//循环此错误相关的数据
foreach (var ent in de.Entries)
{
//获取错误数据Id
var errorId = (long)((ent.Entity as TopBasePoco).ExcelIndex);
//根据State判断修改或删除操作输出不同的错误信息
if (ent.State == EntityState.Deleted)
{
ErrorListVM.EntityList.Add(new ErrorMessage { Index = errorId, Message = CoreProgram._localizer?["Sys.DataCannotDelete"] });
}
else if (ent.State == EntityState.Modified)
{
ErrorListVM.EntityList.Add(new ErrorMessage { Index = errorId, Message = CoreProgram._localizer?["Sys.EditFailed"] });
}
else
{
ErrorListVM.EntityList.Add(new ErrorMessage { Index = errorId, Message = de.Message });
}
}
}
}
//对于其他类型的错误,直接添加错误信息
else
{
if (id != null)
{
ErrorListVM.EntityList.Add(new ErrorMessage { Index = id.Value, Message = e.Message });
}
else
{
ErrorListVM.EntityList.Add(new ErrorMessage { Index = 0, Message = e.Message });
}
}
}
#endregion
#region
/// <summary>
/// 判断数据是否在库中存在重复数据
/// </summary>
/// <param name="Entity">要验证的数据</param>
/// <param name="checkCondition">验证表达式</param>
/// <returns>null代表没有重复</returns>
protected P IsDuplicateData(P Entity, DuplicatedInfo<P> checkCondition)
{
//获取设定的重复字段信息
if (checkCondition != null && checkCondition.Groups.Count > 0)
{
//生成基础Query
var baseExp = DC.Set<P>().AsQueryable();
var modelType = typeof(P);
ParameterExpression para = Expression.Parameter(modelType, "tm");
//循环所有重复字段组
foreach (var group in checkCondition.Groups)
{
List<Expression> conditions = new List<Expression>();
//生成一个表达式,类似于 x=>x.Id != id这是为了当修改数据时验证重复性的时候排除当前正在修改的数据
//在每个组中循环所有字段
List<PropertyInfo> props = new List<PropertyInfo>();
//在每个组中循环所有字段
foreach (var field in group.Fields)
{
Expression exp = field.GetExpression(Entity, para);
if (exp != null)
{
conditions.Add(exp);
}
//将字段名保存,为后面生成错误信息作准备
props.AddRange(field.GetProperties());
}
if (conditions.Count > 0)
{
//循环添加条件并生成Where语句
Expression whereCallExpression = baseExp.Expression;
for (int i = 0; i < conditions.Count; i++)
{
whereCallExpression = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { modelType },
whereCallExpression,
Expression.Lambda<Func<P, bool>>(conditions[i], new ParameterExpression[] { para }));
}
var result = baseExp.Provider.CreateQuery(whereCallExpression);
foreach (var res in result)
{
if (IsOverWriteExistData == false)
{
//循环拼接所有字段名
string AllName = "";
foreach (var prop in props)
{
string name = PropertyHelper.GetPropertyDisplayName(prop);
AllName += name + ",";
}
if (AllName.EndsWith(","))
{
AllName = AllName.Remove(AllName.Length - 1);
}
//如果只有一个字段重复,则拼接形成 xxx字段重复 这种提示
if (props.Count == 1)
{
ErrorListVM.EntityList.Add(new ErrorMessage { Message = CoreProgram._localizer?["Sys.DuplicateError", AllName], Index = Entity.ExcelIndex });
}
//如果多个字段重复,则拼接形成 xxyyzz组合字段重复 这种提示
else if (props.Count > 1)
{
ErrorListVM.EntityList.Add(new ErrorMessage { Message = CoreProgram._localizer?["Sys.DuplicateGroupError", AllName], Index = Entity.ExcelIndex });
}
}
return res as P;
}
}
}
}
return null;
}
#endregion
protected DuplicatedInfo<P> CreateFieldsInfo(params DuplicatedField<P>[] FieldExps)
{
DuplicatedInfo<P> d = new DuplicatedInfo<P>();
d.AddGroup(FieldExps);
return d;
}
/// <summary>
/// 创建一个简单重复数据信息
/// </summary>
/// <param name="FieldExp">重复数据的字段</param>
/// <returns>重复数据信息</returns>
public static DuplicatedField<P> SimpleField(Expression<Func<P, object>> FieldExp)
{
return new DuplicatedField<P>(FieldExp);
}
/// <summary>
/// 创建一个关联到其他表数组中数据的重复信息
/// </summary>
/// <typeparam name="V">关联表类</typeparam>
/// <param name="MiddleExp">指向关联表类数组的Lambda</param>
/// <param name="FieldExps">指向最终字段的Lambda</param>
/// <returns>重复数据信息</returns>
public static DuplicatedField<P> SubField<V>(Expression<Func<P, List<V>>> MiddleExp, params Expression<Func<V, object>>[] FieldExps)
{
return new ComplexDuplicatedField<P, V>(MiddleExp, FieldExps);
}
public ErrorObj GetErrorJson()
{
var mse = new ErrorObj();
mse.Form = new Dictionary<string, string>();
var err = ErrorListVM?.EntityList?.Where(x => x.Index == 0).FirstOrDefault()?.Message;
if (string.IsNullOrEmpty(err))
{
Models.IWtmFile fa = null;
if(Wtm.ServiceProvider == null) {
return mse;
}
var fp = Wtm.ServiceProvider.GetRequiredService<WtmFileProvider>();
fa = fp.GetFile(UploadFileId, true, DC);
xssfworkbook = new XSSFWorkbook(fa.DataStream);
fa.DataStream.Dispose();
var propetys = Template.GetType().GetFields().Where(x => x.FieldType == typeof(ExcelPropety)).ToList();
List<ExcelPropety> excelPropetys = new List<ExcelPropety>();
for (int porpetyIndex = 0; porpetyIndex < propetys.Count(); porpetyIndex++)
{
ExcelPropety ep = (ExcelPropety)propetys[porpetyIndex].GetValue(Template);
excelPropetys.Add(ep);
}
int columnCount = excelPropetys.Count;
//int excelPropetyCount = excelPropetys.Count;
var dynamicColumn = excelPropetys.Where(x => x.DataType == ColumnDataType.Dynamic).FirstOrDefault();
if (dynamicColumn != null)
{
columnCount = columnCount + dynamicColumn.DynamicColumns.Count - 1;
}
ISheet sheet = xssfworkbook.GetSheetAt(0);
var errorStyle = xssfworkbook.CreateCellStyle();
IFont f = xssfworkbook.CreateFont();
f.Color = HSSFColor.Red.Index;
errorStyle.SetFont(f);
errorStyle.IsLocked = true;
foreach (var e in ErrorListVM?.EntityList)
{
if (e.Index > 0)
{
var c = sheet.GetRow((int)(e.Index - 1)).CreateCell(columnCount);
c.CellStyle = errorStyle;
c.SetCellValue(e.Message);
}
}
MemoryStream ms = new MemoryStream();
xssfworkbook.Write(ms);
ms.Position = 0;
var newfile = fp.Upload("Error-" + fa.FileName, ms.Length, ms);
ms.Close();
ms.Dispose();
err = CoreProgram._localizer?["Sys.ImportError"];
mse.Form.Add("Entity.Import", err);
mse.Form.Add("Entity.ErrorFileId", newfile.GetID());
}
else
{
mse.Form.Add("Entity.Import", err);
}
return mse;
}
}
#region
public class ErrorMessage : TopBasePoco
{
[Display(Name = "Sys.RowIndex")]
public long Index { get; set; }
[Display(Name = "Sys.CellIndex")]
public long Cell { get; set; }
[Display(Name = "Sys.ErrorMsg")]
public string Message { get; set; }
}
/// <summary>
/// 错误数据列表
/// </summary>
public class TemplateErrorListVM : BasePagedListVM<ErrorMessage, BaseSearcher>
{
public TemplateErrorListVM()
{
EntityList = new List<ErrorMessage>();
NeedPage = false;
}
protected override IEnumerable<IGridColumn<ErrorMessage>> InitGridHeader()
{
return new List<GridColumn<ErrorMessage>>{
this.MakeGridHeader(x => x.Index, 60),
this.MakeGridHeader(x => x.Message)
};
}
public override IOrderedQueryable<ErrorMessage> GetSearchQuery()
{
return EntityList.AsQueryable().OrderBy(x => x.Index);
}
}
#endregion
}