- 增加 ISelect.WhereDynamicFilter 方法实现动态过滤条件(与前端交互);

This commit is contained in:
28810
2020-05-07 22:54:16 +08:00
parent ebe1b7a34f
commit e3dba006cf
6 changed files with 556 additions and 164 deletions

View File

@ -1025,6 +1025,111 @@ namespace FreeSql.Internal.CommonProvider
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
return this as TSelect;
}
static MethodInfo MethodStringContains = typeof(string).GetMethod("Contains", new[] { typeof(string) });
static MethodInfo MethodStringStartsWith = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
static MethodInfo MethodStringEndsWith = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });
public TSelect WhereDynamicFilter(DynamicFilterInfo filter)
{
if (filter == null) return this as TSelect;
var sb = new StringBuilder();
ParseFilter(DynamicFilterLogic.And, filter, true);
this.Where(sb.ToString());
sb.Clear();
return this as TSelect;
void ParseFilter(DynamicFilterLogic logic, DynamicFilterInfo fi, bool isend)
{
if (string.IsNullOrEmpty(fi.Field) == false)
{
var field = fi.Field.Split('.').Select(a => a.Trim()).ToArray();
Expression exp = null;
if (field.Length == 1)
{
foreach (var tb in _tables)
{
if (tb.Table.ColumnsByCs.TryGetValue(field[0], out var col) &&
tb.Table.Properties.TryGetValue(field[0], out var prop))
{
tb.Parameter = Expression.Parameter(tb.Table.Type, tb.Alias);
exp = Expression.MakeMemberAccess(tb.Parameter, prop);
break;
}
}
if (exp == null) throw new Exception($"无法匹配 {fi.Field}");
}
else
{
var firstTb = _tables[0];
var firstTbs = _tables.Where(a => a.AliasInit == field[0]).ToArray();
if (firstTbs.Length == 1)
{
firstTb = firstTbs[0];
}
firstTb.Parameter = Expression.Parameter(firstTb.Table.Type, firstTb.Alias);
var currentType = firstTb.Table.Type;
Expression currentExp = firstTb.Parameter;
for (var x = 0; x < field.Length; x++)
{
var tmp1 = field[x];
if (_commonUtils.GetTableByEntity(currentType).Properties.TryGetValue(tmp1, out var prop) == false)
throw new ArgumentException($"{currentType.DisplayCsharp()} 无法找到属性名 {tmp1}");
currentType = prop.PropertyType;
currentExp = Expression.MakeMemberAccess(currentExp, prop);
}
exp = currentExp;
}
switch (fi.Operator)
{
case DynamicFilterOperator.Contains: exp = Expression.Call(exp, MethodStringContains, Expression.Constant(fi.Value)); break;
case DynamicFilterOperator.StartsWith: exp = Expression.Call(exp, MethodStringStartsWith, Expression.Constant(fi.Value)); break;
case DynamicFilterOperator.EndsWith: exp = Expression.Call(exp, MethodStringEndsWith, Expression.Constant(fi.Value)); break;
case DynamicFilterOperator.NotContains: exp = Expression.Not(Expression.Call(exp, MethodStringContains, Expression.Constant(fi.Value))); break;
case DynamicFilterOperator.NotStartsWith: exp = Expression.Not(Expression.Call(exp, MethodStringStartsWith, Expression.Constant(fi.Value))); break;
case DynamicFilterOperator.NotEndsWith: exp = Expression.Not(Expression.Call(exp, MethodStringEndsWith, Expression.Constant(fi.Value))); break;
case DynamicFilterOperator.Equals:
case DynamicFilterOperator.Eq: exp = Expression.Equal(exp, Expression.Constant(Utils.GetDataReaderValue(exp.Type, fi.Value), exp.Type)); break;
case DynamicFilterOperator.NotEqual: exp = Expression.NotEqual(exp, Expression.Constant(Utils.GetDataReaderValue(exp.Type, fi.Value), exp.Type)); break;
case DynamicFilterOperator.GreaterThan: exp = Expression.GreaterThan(exp, Expression.Constant(Utils.GetDataReaderValue(exp.Type, fi.Value), exp.Type)); break;
case DynamicFilterOperator.GreaterThanOrEqual: exp = Expression.GreaterThanOrEqual(exp, Expression.Constant(Utils.GetDataReaderValue(exp.Type, fi.Value), exp.Type)); break;
case DynamicFilterOperator.LessThan: exp = Expression.LessThan(exp, Expression.Constant(Utils.GetDataReaderValue(exp.Type, fi.Value), exp.Type)); break;
case DynamicFilterOperator.LessThanOrEqual: exp = Expression.LessThanOrEqual(exp, Expression.Constant(Utils.GetDataReaderValue(exp.Type, fi.Value), exp.Type)); break;
}
var sql = _commonExpression.ExpressionWhereLambda(_tables, exp, null, null, _params);
sb.Append(sql);
}
if (fi.Filters?.Any() == true)
{
if (string.IsNullOrEmpty(fi.Field) == false)
sb.Append(" AND ");
if (fi.Logic == DynamicFilterLogic.Or) sb.Append("(");
for (var x = 0; x < fi.Filters.Count; x++)
ParseFilter(fi.Logic, fi.Filters[x], x == fi.Filters.Count - 1);
if (fi.Logic == DynamicFilterLogic.Or) sb.Append(")");
}
if (isend == false)
{
if (string.IsNullOrEmpty(fi.Field) == false || fi.Filters?.Any() == true)
{
switch (filter.Logic)
{
case DynamicFilterLogic.And: sb.Append(" AND "); break;
case DynamicFilterLogic.Or: sb.Append(" OR "); break;
}
}
}
}
}
public TSelect DisableGlobalFilter(params string[] name)
{
if (_whereGlobalFilter.Any() == false) return this as TSelect;

View File

@ -0,0 +1,84 @@
using FreeSql;
using FreeSql.Internal;
using FreeSql.Internal.CommonProvider;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
namespace FreeSql.Internal.Model
{
/// <summary>
/// 动态过滤条件
/// </summary>
public class DynamicFilterInfo
{
/// <summary>
/// 属性名Name<para></para>
/// 导航属性Parent.Name<para></para>
/// 多表b.Name<para></para>
/// </summary>
public string Field { get; set; }
/// <summary>
/// 操作符
/// </summary>
public DynamicFilterOperator Operator { get; set; }
/// <summary>
/// 值
/// </summary>
public string Value { get; set; }
/// <summary>
/// Filters 下的逻辑运算符
/// </summary>
public DynamicFilterLogic Logic { get; set; }
/// <summary>
/// 子过滤条件,它与当前的逻辑关系是 And<para></para>
/// 注意:当前 Field 可以留空
/// </summary>
public List<DynamicFilterInfo> Filters { get; set; }
}
public enum DynamicFilterLogic { And, Or }
public enum DynamicFilterOperator
{
/// <summary>
/// like
/// </summary>
Contains,
StartsWith,
EndsWith,
NotContains,
NotStartsWith,
NotEndsWith,
/// <summary>
/// =
/// </summary>
Equals,
Eq,
/// <summary>
/// &lt;&gt;
/// </summary>
NotEqual,
/// <summary>
/// &gt;
/// </summary>
GreaterThan,
/// <summary>
/// &gt;=
/// </summary>
GreaterThanOrEqual,
/// <summary>
/// &lt;
/// </summary>
LessThan,
/// <summary>
/// &lt;=
/// </summary>
LessThanOrEqual,
}
}