1、使用特性标记属性
2、将filter转换为expression
/// <summary> /// 运算 /// </summary> public class Operater { /// <summary> /// 等于 /// </summary> public const string Equal = "eq"; /// <summary> /// 不等于 /// </summary> public const string NotEqual = "ne"; /// <summary> /// 大于 /// </summary> public const string GreaterThan = "gt"; /// <summary> /// 大于等于 /// </summary> public const string GreaterThanOrEqual = "gte"; /// <summary> /// 小于 /// </summary> public const string LessThan = "lt"; /// <summary> /// 小于等于 /// </summary> public const string LessThanOrEqual = "lte"; /// <summary> /// 包含 /// </summary> public const string Contains = "cn"; /// <summary> /// 不包含 /// </summary> public const string NotContains = "nc"; /// <summary> /// 包含 /// </summary> public const string In = "in"; /// <summary> /// 以XX开头 /// </summary> public const string StartsWith = "sw"; public const string StringGreaterThanOrEqual = "sgte"; public const string StringLessThanOrEqual = "slte"; }
public interface IFilter { /// <summary> /// 排序字段 /// </summary> string sidx { get; set; } /// <summary> /// 类型 asc/desc /// </summary> string sord { get; set; } /// <summary> /// 当前页码 /// </summary> int page { get; set; } /// <summary> /// 每页显示的数据量 /// </summary> int rows { get; set; } }
public abstract class QueryFilter : IFilter { public QueryFilter() { sidx = "Id"; this.sord = "desc"; this.page = 1; this.rows = 10; } public QueryFilter(string sidx,string sord,int page,int rows) { this.sidx = sidx; this.sord = sord; this.page = page; this.rows = rows; } /// <summary> /// 排序字段 /// </summary> public string sidx { get; set; } /// <summary> /// 类型 asc/desc /// </summary> public string sord { get; set; } /// <summary> /// 当前页码 /// </summary> public int page { get; set; } /// <summary> /// 每页显示的数据量 /// </summary> public int rows { get; set; } }
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] public class FieldFilterAttribute : Attribute { public string FieldName { get; set; } public string Operater { get; set; } public FieldFilterAttribute(string operater) { this.Operater = operater; } public FieldFilterAttribute(string fieldName, string operater) { this.FieldName = fieldName; this.Operater = operater; } }
public static class MemberInfoExtension { public static bool HasCustomAttribute<T>(this MemberInfo prop) where T : Attribute { return prop.GetCustomAttribute<T>() != null; } }
public static class StringExtension { /// <summary> /// 判断字符串是否为空或null /// </summary> public static bool IsEmpty(this string value) { return ((value == null) || (value.Length == 0)); } /// <summary> /// 判断字符串是否不为空 /// </summary> public static bool IsNotEmpty(this string value) { return !value.IsEmpty(); } }
public static class ModelFilterExtention { /// <summary> /// 转换为表达式 /// </summary> /// <typeparam name="TModel">过滤实体</typeparam> /// <param name="filter">过滤对象</param> /// <param name="alias">别名</param> /// <returns></returns> public static Expression<Func<TModel, bool>> ToExpression<TModel>(this IFilter filter, string alias = "x") where TModel : class { var parameter = Expression.Parameter(typeof(TModel), alias); var expressions = filter.ToExpressions<TModel>(parameter); Expression expression = null; foreach (var exp in expressions) { if (expression == null) { expression = exp; } else { expression = Expression.And(expression, exp); } } if (expression == null) { return null; } else { return Expression.Lambda<Func<TModel, bool>>(expression, parameter); } } public static IEnumerable<Expression> ToExpressions<TModel>(this IFilter filter, ParameterExpression parameter) where TModel : class { var modelType = typeof(TModel); var properties = filter.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public) .Where(x => x.HasCustomAttribute<FieldFilterAttribute>()); foreach (var property in properties) { var attribute = property.GetCustomAttribute<FieldFilterAttribute>(); if (attribute == null) { continue; } var fieldName = property.Name; if (attribute.FieldName.IsNotEmpty()) { fieldName = attribute.FieldName; } var fieldValue = property.GetValue(filter); if (fieldName.IsEmpty() || fieldValue.Equals("null")) { continue; } var member = Expression.Property(parameter, modelType.GetProperty(fieldName)); var operater = property.GetCustomAttribute<FieldFilterAttribute>().Operater; Expression expression; switch (operater) { case Operater.GreaterThanOrEqual: expression = Expression.GreaterThanOrEqual(member, Expression.Constant(fieldValue, member.Type)); break; case Operater.LessThan: expression = Expression.LessThan(member, Expression.Constant(fieldValue, member.Type)); break; case Operater.LessThanOrEqual: expression = Expression.LessThanOrEqual(member, Expression.Constant(fieldValue, member.Type)); break; case Operater.GreaterThan: expression = Expression.GreaterThan(member, Expression.Constant(fieldValue, member.Type)); break; case Operater.Contains: expression = Expression.Call(member, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), Expression.Constant(fieldValue, typeof(string))); break; case Operater.NotContains: expression = Expression.Not(Expression.Call(member, typeof(string).GetMethod("Contains"), Expression.Constant(fieldValue, typeof(string)))); break; case Operater.In: var fieldValueList = Expression.Constant(fieldValue.ToString().Split(',').ToList(), typeof(List<string>)); expression = Expression.Call(fieldValueList, typeof(List<string>).GetMethod("Contains"), member); break; case Operater.StartsWith: expression = Expression.Call(member, typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) }), Expression.Constant(fieldValue, typeof(string))); break; case Operater.StringGreaterThanOrEqual: expression = Expression.GreaterThanOrEqual( Expression.Call(member, typeof(String).GetMethod("CompareTo", new Type[] { typeof(String) }), Expression.Constant(fieldValue, typeof(string))), Expression.Constant(0, typeof(Int32))); break; case Operater.StringLessThanOrEqual: expression = Expression.LessThanOrEqual( Expression.Call(member, typeof(String).GetMethod("CompareTo", new Type[] { typeof(String) }), Expression.Constant(fieldValue, typeof(string))), Expression.Constant(0, typeof(Int32))); break; case Operater.NotEqual: expression = Expression.NotEqual(member, Expression.Constant(fieldValue, member.Type)); break; case Operater.Equal: default: expression = Expression.Equal(member, Expression.Constant(fieldValue, member.Type)); break; } yield return expression; } } /// <summary> /// 获取表达式() /// </summary> /// <typeparam name="TModel"></typeparam> /// <param name="field"></param> /// <param name="alias"></param> /// <returns></returns> public static Expression<Func<Type, object>> GetExpression<Type>(string field, string alias) { var parameterExpression = Expression.Parameter(typeof(Type), alias); var memberExpression = Expression.Property(parameterExpression, typeof(Type).GetProperty(field)); Expression conversion = Expression.Convert(memberExpression, typeof(object)); return Expression.Lambda<Func<Type, dynamic>>(conversion, parameterExpression); } }
/// <summary> /// 用户查询 /// </summary> public class MemberViewFilter : QueryFilter { [Display(Name = "用户名")] [FieldFilter(Operater.Equal)] public string UserName { get; set; } [Display(Name = "手机号码")] [FieldFilter(Operater.Equal)] public string Password { get; set; } }
[HttpPost] public IActionResult Query(MemberViewFilter filter) { var expression = filter.ToExpression<Member>(); List<Member> list; using (EFDbContext db = new EFDbContext()) { list = db.Set<Member>().Where(expression).ToList(); } return Json(list); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
2015-09-08 C# 创建文件