#nullable enable
|
using Furion.DatabaseAccessor;
|
using Furion.FriendlyException;
|
using System.ComponentModel;
|
using System.Linq.Expressions;
|
using System.Reflection;
|
using System.Security.Cryptography.X509Certificates;
|
using System.Xml.Linq;
|
|
namespace Admin.NET.Core
|
{
|
public static class DataConvertUtil
|
{
|
/// <summary>
|
/// 将对象转换为Excel数据
|
/// </summary>
|
/// <typeparam name="T"></typeparam>
|
/// <param name="source"></param>
|
/// <param name="sysDictTypeRep"></param>
|
/// <param name="sysDictDataRep"></param>
|
/// <param name="headers"></param>
|
/// <param name="data"></param>
|
/// <param name="sheetName"></param>
|
public static void ToExcelData<T>(List<T> source,
|
IRepository<SysDictType, MasterDbContextLocator> sysDictTypeRep,
|
IRepository<SysDictData, MasterDbContextLocator> sysDictDataRep,
|
out List<string> headers, out List<List<object>> data, out string sheetName)
|
{
|
headers = new List<string>();
|
data = new List<List<object>>();
|
var type = typeof(T);
|
sheetName = ((DescriptionAttribute?)type.GetCustomAttribute(typeof(DescriptionAttribute), true))?.Description ?? "无";
|
List<string> enumClassNames = new();
|
foreach (var field in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
{
|
if ("Id".Equals(field.Name)) continue;
|
if (field.Name.EndsWith("Id")) continue;
|
headers.Add(((DescriptionAttribute?)field.GetCustomAttribute(typeof(DescriptionAttribute), true))?.Description ?? "无");
|
var dataType = StringUtil.ParseTrueType2(field.PropertyType.FullName ?? "");
|
if (TypeUtil.GetType(dataType)?.IsEnum ?? false)
|
{
|
if (!enumClassNames.Contains(dataType))
|
{
|
enumClassNames.Add(dataType);
|
}
|
}
|
}
|
|
var dictTypeList = sysDictTypeRep.DetachedEntities.Where(x => enumClassNames.Contains(x.EnumClassName)).ToList();
|
List<long> dictTypeIds = dictTypeList.Select(x => x.Id).ToList();
|
Dictionary<long, SysDictType> dictTypeDictionary = new();
|
dictTypeList.ForEach(x => dictTypeDictionary.Add(x.Id, x));
|
var dictDataList = sysDictDataRep.DetachedEntities.Where(x => dictTypeIds.Contains(x.TypeId)).ToList();
|
dictDataList.ForEach(x =>
|
{
|
if (dictTypeDictionary.ContainsKey(x.TypeId))
|
{
|
var dictType = dictTypeDictionary[x.TypeId];
|
if (dictType?.SysDictDatas == null)
|
{
|
if (dictType != null)
|
{
|
dictType.SysDictDatas = new List<SysDictData>();
|
}
|
}
|
dictType?.SysDictDatas?.Add(x);
|
}
|
});
|
Dictionary<string, string> map = new();
|
dictTypeList.ForEach(x =>
|
{
|
if (x?.SysDictDatas != null)
|
{
|
foreach (SysDictData dictData in x.SysDictDatas)
|
{
|
if (dictData != null) map.Add(x.EnumClassName + "#" + dictData.Code, dictData.Value);
|
}
|
}
|
});
|
|
foreach (var t in source)
|
{
|
List<object> objectList = new();
|
foreach (var field in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
{
|
var fieldName = field.Name;
|
if ("Id".Equals(fieldName)) continue;
|
if (field.Name.EndsWith("Id")) continue;
|
var v = t?.GetType()?.GetProperty(fieldName)?.GetValue(t);
|
var dataType = StringUtil.ParseTrueType2(field.PropertyType.FullName ?? "");
|
if (TypeUtil.GetType(dataType)?.IsEnum ?? false)
|
{
|
v = Convert.ToInt32(v);
|
if (map.ContainsKey(dataType + "#" + v)) v = map[dataType + "#" + v];
|
}
|
else if ("System.DateTimeOffset".Equals(dataType))
|
{
|
v = ExcelDateUtil.ToInt(
|
new DateTimeOffset(Convert.ToDateTime(((DateTimeOffset?)v)?.ToString("yyyy-MM-dd") ?? "1900-01-01")));
|
}
|
else if ("System.DateTime".Equals(dataType))
|
{
|
v = ExcelDateUtil.ToInt(
|
Convert.ToDateTime(((DateTime?)v)?.ToString("yyyy-MM-dd") ?? "1900-01-01"));
|
}
|
objectList.Add(v ?? "");
|
}
|
data.Add(objectList);
|
}
|
}
|
|
/// <summary>
|
/// 将对象转换为Excel数据
|
/// </summary>
|
/// <typeparam name="T"></typeparam>
|
/// <param name="source"></param>
|
/// <param name="sysDictTypeRep"></param>
|
/// <param name="sysDictDataRep"></param>
|
/// <param name="headers"></param>
|
/// <param name="data"></param>
|
/// <param name="sheetName"></param>
|
/// <param name="className"></param>
|
public static void ToExcelData<T>(List<T> source,
|
IRepository<SysDictType, MasterDbContextLocator> sysDictTypeRep,
|
IRepository<SysDictData, MasterDbContextLocator> sysDictDataRep,
|
out List<string> headers, out List<List<object>> data, out string sheetName, out string className)
|
{
|
ToExcelData(source, sysDictTypeRep, sysDictDataRep, out headers, out data, out sheetName);
|
var type = typeof(T);
|
className = type.Name ?? "";
|
if (className.EndsWith("Output"))
|
{
|
className = className[..^"Output".Length];
|
}
|
}
|
|
|
/// <summary>
|
/// 根据键数字生成内容字符串
|
/// </summary>
|
/// <typeparam name="T"></typeparam>
|
/// <param name="t"></param>
|
/// <param name="keys"></param>
|
/// <returns></returns>
|
public static string ParseStrByKeys<T>(this T t, string[] keys)
|
{
|
var type = typeof(T);
|
Dictionary<string, PropertyInfo> namePropertyInfoDict = new();
|
foreach (var field in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
{
|
var fName = field?.Name ?? "";
|
if (keys.Contains(fName))
|
{
|
namePropertyInfoDict[fName] = field ?? null!;
|
}
|
}
|
var str = "";
|
|
foreach (var k in keys)
|
{
|
str += StringUtil.SplitChar() + namePropertyInfoDict[k]?.GetValue(t) ?? "";
|
}
|
|
return str;
|
}
|
|
/// <summary>
|
/// 将Excel数据转换为对象列表
|
/// </summary>
|
/// <typeparam name="T"></typeparam>
|
/// <param name="headers"></param>
|
/// <param name="data"></param>
|
/// <param name="sheetName"></param>
|
/// <returns></returns>
|
public static List<T> ToObjectList<T>(List<string> headers, List<List<object?>> data, string sheetName, string[] keys, int dataStartLine, out Dictionary<string, T> dict)
|
{
|
var type = typeof(T);
|
//去掉此验证 【Editby shaocx,2024-04-15】
|
//var sheetName2 = ((DescriptionAttribute?)type.GetCustomAttribute(typeof(DescriptionAttribute), true))?.Description ?? "无";
|
//if (!sheetName2.Equals(sheetName))
|
//{
|
// throw Oops.Oh(ErrorCode.Excel003);
|
//}
|
|
Dictionary<int, string> indexFieldNameDict = new();
|
Dictionary<int, string> indexFieldTypeDict = new();
|
Dictionary<int, PropertyInfo> indexPropertyInfoDict = new();
|
Dictionary<string, PropertyInfo> namePropertyInfoDict = new();
|
foreach (var field in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
{
|
var desc = ((DescriptionAttribute?)field.GetCustomAttribute(typeof(DescriptionAttribute), true))?.Description ?? "无";
|
var fName = field.Name ?? "";
|
var fType = StringUtil.ParseTrueType2(field.PropertyType.FullName ?? "");
|
for (var i = 0; i < headers.Count; i++)
|
{
|
var header = headers[i];
|
if (header.Equals(desc))
|
{
|
indexFieldNameDict[i] = fName;
|
indexFieldTypeDict[i] = fType;
|
indexPropertyInfoDict[i] = field;
|
namePropertyInfoDict[fName] = field;
|
break;
|
}
|
}
|
}
|
|
List<T> outputs = new();
|
foreach (var record in data)
|
{
|
var output = Activator.CreateInstance(type, true);
|
for (var i = 0; i < record.Count; i++)
|
{
|
if ("System.String".Equals(indexFieldTypeDict[i]))
|
{
|
indexPropertyInfoDict[i].SetValue(output, record[i]?.ToString() ?? "", null);
|
}
|
else if ("System.Int32".Equals(indexFieldTypeDict[i]))
|
{
|
indexPropertyInfoDict[i].SetValue(output, int.Parse(record[i]?.ToString() ?? "0"), null);
|
}
|
else if ("System.Int64".Equals(indexFieldTypeDict[i]))
|
{
|
indexPropertyInfoDict[i].SetValue(output, long.Parse(record[i]?.ToString() ?? "0"), null);
|
}
|
else if ("System.Single".Equals(indexFieldTypeDict[i]))
|
{
|
indexPropertyInfoDict[i].SetValue(output, float.Parse(record[i]?.ToString() ?? "0.0"), null);
|
}
|
else if ("System.Double".Equals(indexFieldTypeDict[i]))
|
{
|
indexPropertyInfoDict[i].SetValue(output, double.Parse(record[i]?.ToString() ?? "0.0"), null);
|
}
|
else if ("System.Decimal".Equals(indexFieldTypeDict[i]))
|
{
|
indexPropertyInfoDict[i].SetValue(output, decimal.Parse(record[i]?.ToString() ?? "0.0"), null);
|
}
|
else if ("System.Boolean".Equals(indexFieldTypeDict[i]))
|
{
|
indexPropertyInfoDict[i].SetValue(output, bool.Parse(record[i]?.ToString() ?? "False"), null);
|
}
|
else if ("System.Byte".Equals(indexFieldTypeDict[i]))
|
{
|
indexPropertyInfoDict[i].SetValue(output, byte.Parse(record[i]?.ToString() ?? "0"), null);
|
}
|
else if (TypeUtil.GetType(indexFieldTypeDict[i])?.IsEnum ?? false)
|
{
|
indexPropertyInfoDict[i].SetValue(output,
|
TypeUtil.GetType(indexFieldTypeDict[i])?.GetEnumByDescription(record[i]?.ToString() ?? ""), null);
|
}
|
else if ("System.DateTime".Equals(indexFieldTypeDict[i]))
|
{
|
indexPropertyInfoDict[i].SetValue(output,
|
ExcelDateUtil.ToDateTime(long.Parse(record[i]?.ToString() ?? "1")), null);
|
}
|
else if ("System.DateTimeOffset".Equals(indexFieldTypeDict[i]))
|
{
|
indexPropertyInfoDict[i].SetValue(output,
|
ExcelDateUtil.ToDateTimeOffset(long.Parse(record[i]?.ToString() ?? "1")), null);
|
}
|
}
|
if (output != null)
|
{
|
outputs.Add((T)output);
|
}
|
}
|
|
|
|
dict = new Dictionary<string, T>();
|
foreach (var x in outputs)
|
{
|
var key = string.Empty;
|
foreach (var k in keys)
|
{
|
key += StringUtil.SplitChar() + namePropertyInfoDict[k]?.GetValue(x) ?? "";
|
}
|
|
if (!string.IsNullOrEmpty(key))
|
{
|
if (dict.ContainsKey(key)) throw Oops.Oh($"在{sheetName}页的第{dataStartLine}行, 唯一键冲突");
|
dict.Add(key, x);
|
}
|
|
dataStartLine += 1;
|
};
|
|
return outputs;
|
}
|
|
|
|
/// <summary>
|
/// 获取已存在的数据
|
/// </summary>
|
/// <typeparam name="T"></typeparam>
|
/// <param name="records"></param>
|
/// <returns></returns>
|
public static List<Dictionary<string, object>> ParseUniqueKeyValueDictList<T>(this List<T> records, List<string> keys, int dataStartLine, string sheetName)
|
{
|
|
if (keys.Count <= 0)
|
{
|
throw Oops.Oh(ErrorCode.Key001);
|
}
|
|
if (records.Count <= 0)
|
{
|
return new List<Dictionary<string, object>>();
|
}
|
|
Type type = typeof(T);
|
List<Dictionary<string, object>> uniqueKeyValueDictList = new();
|
var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => keys.Contains(x.Name)).ToList();
|
Dictionary<string, PropertyInfo> namePropDict = new();
|
props.ForEach(x => namePropDict.Add(x.Name, x));
|
|
|
List<string> keyStrs = new();
|
|
records.ForEach(x =>
|
{
|
Dictionary<string, object> dict = new();
|
string keyStr = string.Empty;
|
keys.ForEach(y =>
|
{
|
var value = namePropDict[y]?.GetValue(x) ?? "";
|
if (string.IsNullOrWhiteSpace(value + "")) throw Oops.Oh($"在{sheetName}页的第{dataStartLine}行, {y}的取值不能为空");
|
keyStr += StringUtil.SplitChar() + value;
|
dict.Add(y, value);
|
});
|
if (keyStrs.Contains(keyStr)) throw Oops.Oh($"在{sheetName}页的第{dataStartLine}行, 唯一键冲突");
|
keyStrs.Add(keyStr);
|
uniqueKeyValueDictList.Add(dict);
|
dataStartLine++;
|
});
|
|
return uniqueKeyValueDictList;
|
}
|
|
/// <summary>
|
/// 生成动态查询已存在记录的lamda表达式列表
|
/// </summary>
|
/// <typeparam name="T"></typeparam>
|
/// <param name="keys"></param>
|
/// <param name="uniqueKeyValueDictList"></param>
|
/// <param name="size"></param>
|
/// <returns></returns>
|
public static List<Expression<Func<T, bool>>> GetExpressionListByUniqueDict<T>(List<string> keys,
|
List<Dictionary<string, object>> uniqueKeyValueDictList, int size)
|
{
|
if (keys.Count <= 0) throw Oops.Oh(ErrorCode.Key001);
|
var uniqueKeyValueDictListArray = uniqueKeyValueDictList.SplitList(size);
|
Type type = typeof(T);
|
var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => keys.Contains(x.Name)).ToList();
|
Dictionary<string, PropertyInfo> namePropDict = new();
|
props.ForEach(x => namePropDict.Add(x.Name, x));
|
List<Expression<Func<T, bool>>> filters = new();
|
foreach (var dictList in uniqueKeyValueDictListArray)
|
{
|
var parameter = Expression.Parameter(type, "m");
|
Expression? expression = null;
|
foreach (var item in dictList)
|
{
|
Expression? expressionItem = null;
|
foreach (var key in keys)
|
{
|
Expression expProperty = Expression.Property(parameter, key);
|
Expression<Func<object?>> valueLamda = () => item[key];
|
Expression expValue = Expression.Convert(valueLamda.Body, namePropDict[key].PropertyType);
|
expressionItem = expressionItem == null ? Expression.Equal(expProperty, expValue) :
|
Expression.AndAlso(expressionItem, Expression.Equal(expProperty, expValue));
|
}
|
expression = (expression == null) ? expressionItem : Expression.OrElse(expression, expressionItem ?? null!);
|
}
|
|
Expression<Func<T, bool>> filter = ((Expression<Func<T, bool>>)Expression.Lambda(expression ?? null!, parameter));
|
filters.Add(filter);
|
}
|
return filters;
|
}
|
|
/// <summary>
|
/// 生成动态查询已存在记录的投影lamda表达式列表
|
/// </summary>
|
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="S"></typeparam>
|
/// <param name="keys"></param>
|
/// <returns></returns>
|
public static Expression<Func<TSource, TResult>> GetSelectExpressionListByUniqueDict<TSource, TResult>(List<string> keys)
|
{
|
if (keys.Count <= 0)
|
{
|
throw Oops.Oh(ErrorCode.Key001);
|
}
|
Type type = typeof(TSource);
|
var left = Expression.Parameter(type, "x");
|
var v0 = Expression.New(typeof(TResult));
|
List<MemberBinding> bindingList = new();
|
foreach (var item in keys)
|
{
|
MemberInfo speciesMember = typeof(TResult).GetMember(item)[0];
|
MemberExpression mem = Expression.Property(left, item);
|
MemberBinding memberBinding = Expression.Bind(speciesMember, mem);
|
bindingList.Add(memberBinding);
|
}
|
Expression body = Expression.MemberInit(v0, bindingList);
|
Expression<Func<TSource, TResult>> selector = (Expression<Func<TSource, TResult>>)Expression.Lambda(body, left);
|
return selector;
|
}
|
|
/// <summary>
|
/// 获取字典生成的键字符串
|
/// </summary>
|
/// <typeparam name="T"></typeparam>
|
/// <param name="t"></param>
|
/// <param name="keys"></param>
|
/// <returns></returns>
|
public static string GetKey<T>(T t, string[] keys)
|
{
|
Type type = typeof(T);
|
List<Dictionary<string, object>> uniqueKeyValueDictList = new();
|
var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => keys.Contains(x.Name)).ToList();
|
Dictionary<string, PropertyInfo> namePropDict = new();
|
props.ForEach(x => namePropDict.Add(x.Name, x));
|
string key = "";
|
foreach (var item in keys)
|
{
|
key += StringUtil.SplitChar() + namePropDict[item]?.GetValue(t) ?? "";
|
}
|
return key;
|
}
|
}
|
}
|