342 lines
12 KiB
C#
342 lines
12 KiB
C#
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;
|
||
}
|
||
}
|
||
}
|