iotgateway/WalkingTec.Mvvm/WalkingTec.Mvvm.Core/Support/DuplicateInfo.cs
2021-12-14 14:10:44 +08:00

342 lines
12 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using WalkingTec.Mvvm.Core.Extensions;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// 重复数据组
/// </summary>
/// <typeparam name="T">重复数据类</typeparam>
public class DuplicatedGroup<T>
{
public List<DuplicatedField<T>> Fields { get; set; }
}
/// <summary>
/// 重复数据信息
/// </summary>
/// <typeparam name="T">数据类</typeparam>
public class DuplicatedInfo<T>
{
//重复数据分组
public List<DuplicatedGroup<T>> Groups { get; set; }
public DuplicatedInfo()
{
Groups = new List<DuplicatedGroup<T>>();
}
/// <summary>
/// 添加一组重复信息,一组中的多个字段必须同时重复才认为是重复数据
/// </summary>
/// <param name="FieldExps">一个或多个重复数据字段</param>
public DuplicatedInfo<T> AddGroup(params DuplicatedField<T>[] FieldExps)
{
DuplicatedGroup<T> newGroup = new DuplicatedGroup<T>()
{
Fields = new List<DuplicatedField<T>>()
};
foreach (var exp in FieldExps)
{
newGroup.Fields.Add(exp);
}
Groups.Add(newGroup);
return this;
}
}
/// <summary>
/// 简单重复数据字段信息
/// </summary>
/// <typeparam name="T">重复数据类</typeparam>
public class DuplicatedField<T>
{
//直接可顺序关联出的字段
protected Expression<Func<T, object>> _directFieldExp { get; set; }
public virtual List<PropertyInfo> GetProperties()
{
List<PropertyInfo> rv = new List<PropertyInfo>
{
PropertyHelper.GetPropertyInfo(_directFieldExp)
};
return rv;
}
/// <summary>
/// 根据设定的字段生成查询重复数据的Lambda最终返回类似 x=>x.property == val的lambda
/// </summary>
/// <param name="Entity">要验证字段的实体类</param>
/// <param name="para">ParameterExpression</param>
/// <returns></returns>
public virtual Expression GetExpression(T Entity, ParameterExpression para)
{
var propName = PropertyHelper.GetPropertyName(_directFieldExp);
var prop = PropertyHelper.GetPropertyInfo(_directFieldExp);
var func = _directFieldExp.Compile();
var val = func.Invoke(Entity);
////如果字段值为null则跳过因为一般情况下null值不会被认为重复
//if (val == null)
//{
// return res;
//}
//如果字段值是空字符串,则跳过
if (val is string && val.ToString() == string.Empty)
{
var requiredAttrs = prop.GetCustomAttributes(typeof(RequiredAttribute), false).ToList();
if (requiredAttrs == null || requiredAttrs.Count == 0)
{
return null;
}
else
{
var requiredAtt = requiredAttrs[0] as RequiredAttribute;
if (requiredAtt.AllowEmptyStrings == true)
{
return null;
}
}
}
//生成一个表达式,类似于 x=>x.field == val
var splits = propName.Split('.');
var idproperty = typeof(T).GetSingleProperty(splits[0]);
Expression left = Expression.Property(para, idproperty);
for (int i = 1; i < splits.Length; i++)
{
var tempproperty = typeof(T).GetSingleProperty(splits[i]);
left = Expression.Property(left, tempproperty);
}
if (val != null && left.Type.IsGeneric(typeof(Nullable<>)))
{
left = Expression.Property(left, "Value");
}
if (left.Type == typeof(string))
{
left = Expression.Call(left, typeof(String).GetMethod("Trim", Type.EmptyTypes));
}
if (val is string)
{
val = val.ToString().Trim();
}
var right = Expression.Constant(val);
var equal = Expression.Equal(left, right);
return equal;
}
protected DuplicatedField()
{
}
/// <summary>
/// 创建一个包含可顺序关联出字段的简单重复字段信息
/// </summary>
/// <param name="FieldExp">字段</param>
/// <returns>字段信息</returns>
public DuplicatedField(Expression<Func<T, object>> FieldExp)
{
_directFieldExp = FieldExp;
}
}
/// <summary>
/// 复杂重复字段信息接口
/// </summary>
public interface IComplexDuplicatedField
{
Type GetMiddleTableType();
}
/// <summary>
/// 复杂重复数据字段信息
/// </summary>
/// <typeparam name="T">重复数据类</typeparam>
/// <typeparam name="V">重复数据关联的List中的类</typeparam>
public class ComplexDuplicatedField<T, V> : DuplicatedField<T>, IComplexDuplicatedField
{
/// <summary>
/// 中间字段
/// </summary>
private Expression<Func<T, List<V>>> _middleExp { get; set; }
/// <summary>
/// 最终字段
/// </summary>
private List<Expression<Func<V, object>>> _subFieldExps { get; set; }
protected ComplexDuplicatedField()
{
}
/// <summary>
/// 创建一个复杂字段
/// </summary>
/// <param name="MiddleExp">中间字段类</param>
/// <param name="FieldExps">最终字段类</param>
/// <returns></returns>
public ComplexDuplicatedField(Expression<Func<T, List<V>>> MiddleExp, params Expression<Func<V, object>>[] FieldExps)
{
_middleExp = MiddleExp;
_subFieldExps = new List<Expression<Func<V, object>>>();
_subFieldExps.AddRange(FieldExps);
}
public Type GetMiddleTableType()
{
return typeof(V);
}
/// <summary>
/// 生成验证复杂字段是否重复的Lambda
/// </summary>
/// <param name="Entity">源数据</param>
/// <param name="para">源数据类型</param>
/// <returns>Where语句</returns>
public override Expression GetExpression(T Entity, ParameterExpression para)
{
ParameterExpression midPara = Expression.Parameter(typeof(V), "tm2");
//获取中间表的List
var list = _middleExp.Compile().Invoke(Entity);
if (list == null)
{
return null;
}
List<Expression> allExp = new List<Expression>();
Expression rv = null;
//循环中间表数据
foreach (var li in list)
{
List<Expression> innerExp = new List<Expression>();
bool needBreak = false;
//循环中间表要检查重复的字段
foreach (var SubFieldExp in _subFieldExps)
{
//拼接字段表达式使left等于类似 x.field 的形式
Expression left = Expression.Property(midPara, SubFieldExp.GetPropertyName());
//如果字段是nullable类型的则拼接value形成类似 x.field.Value的形式
if (left.Type.IsGeneric(typeof(Nullable<>)) == true)
{
left = Expression.Property(left, "Value");
}
//如果字段是string类型则拼接trim形成类似 x.field.Trim()的形式
if (left.Type == typeof(string))
{
left = Expression.Call(left, typeof(String).GetMethod("Trim", Type.EmptyTypes));
}
//使用当前循环的中间表的数据获取字段的值
object vv = SubFieldExp.Compile().Invoke(li);
//如果值为空则跳过
if (vv == null)
{
needBreak = true;
continue;
}
//如果值为空字符串且没要求必填,则跳过
if (vv is string && vv.ToString() == "")
{
var requiredAttrs = li.GetType().GetSingleProperty(SubFieldExp.GetPropertyName()).GetCustomAttributes(typeof(RequiredAttribute), false).ToList();
if (requiredAttrs == null || requiredAttrs.Count == 0)
{
needBreak = true;
continue;
}
else
{
var requiredAtt = requiredAttrs[0] as RequiredAttribute;
if (requiredAtt.AllowEmptyStrings == true)
{
needBreak = true;
continue;
}
}
}
//如果值为字符串调用trim函数
if (vv is string)
{
vv = vv.ToString().Trim();
}
//拼接形成 x.field == value的形式
ConstantExpression right = Expression.Constant(vv);
BinaryExpression equal = Expression.Equal(left, right);
innerExp.Add(equal);
}
if (needBreak)
{
continue;
}
//拼接多个 x.field==value形成 x.field==value && x.field1==value1 .....的形式
Expression exp = null;
if (innerExp.Count == 1)
{
exp = innerExp[0];
}
if (innerExp.Count > 1)
{
exp = Expression.And(innerExp[0], innerExp[1]);
for (int i = 2; i < innerExp.Count; i++)
{
exp = Expression.And(exp, innerExp[i]);
}
}
//调用any函数形成 .Any(x=> x.field==value && x.field1==value1....)的形式
if (exp != null)
{
var any = Expression.Call(
typeof(Enumerable),
"Any",
new Type[] { typeof(V) },
Expression.Property(para, _middleExp.GetPropertyName()),
Expression.Lambda<Func<V, bool>>(exp, new ParameterExpression[] { midPara }));
allExp.Add(any);
}
}
//拼接多个any函数形成 .Any(x=> x.field==value && x.field1==value1....) || .Any(x=> x.field==value && x.field1==value1....)的形式并返回
if (allExp.Count == 1)
{
rv = allExp[0];
}
if (allExp.Count > 1)
{
rv = Expression.OrElse(allExp[0], allExp[1]);
for (int i = 2; i < allExp.Count; i++)
{
rv = Expression.OrElse(rv, allExp[i]);
}
}
return rv;
}
/// <summary>
/// 获取字段属性
/// </summary>
/// <returns>字段属性列表</returns>
public override List<PropertyInfo> GetProperties()
{
List<PropertyInfo> rv = new List<PropertyInfo>();
foreach (var subField in _subFieldExps)
{
var pro = subField.GetPropertyInfo();
if (pro != null)
{
rv.Add(pro);
}
}
return rv;
}
}
}