diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml
index c941a15d9..a7a94fcda 100644
--- a/FreeSql.DbContext/FreeSql.DbContext.xml
+++ b/FreeSql.DbContext/FreeSql.DbContext.xml
@@ -758,13 +758,5 @@
-
-
- 批量注入 Repository,可以参考代码自行调整
-
-
-
-
-
diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml
index fdde4800e..3805d19fa 100644
--- a/FreeSql/FreeSql.xml
+++ b/FreeSql/FreeSql.xml
@@ -1087,6 +1087,93 @@
+
+
+ 动态创建实体类型
+
+
+
+
+ 配置Class
+
+ 类名
+ 类标记的特性[Table(Name = "xxx")] [Index(xxxx)]
+
+
+
+
+ 获取类型构建器,可作为要构建的Type来引用
+
+
+
+
+ 配置属性
+
+ 属性名称
+ 属性类型
+ 属性标记的特性-支持多个
+
+
+
+
+ 配置属性
+
+ 属性名称
+ 属性类型
+ 该属性是否重写父类属性
+ 属性标记的特性-支持多个
+
+
+
+
+ 配置属性
+
+ 属性名称
+ 属性类型
+ 该属性是否重写父类属性
+ 属性默认值
+ 属性标记的特性-支持多个
+
+
+
+
+ 配置父类
+
+ 父类类型
+
+
+
+
+ Override属性
+
+
+
+
+
+ Emit动态创建出Class - Type
+
+
+
+
+
+ Emit动态创建出Class - Type,不附带获取TableInfo
+
+
+
+
+
+ 首字母小写
+
+
+
+
+
+
+ 首字母大写
+
+
+
+
获取实体的主键值,以 "*|_,[,_|*" 分割,当任意一个主键属性无值时,返回 ""
@@ -4615,6 +4702,13 @@
动态过滤条件
+
+
+ 使用所有逻辑运算符,默认为False。
+ False:按照原来的模式,只有分组的逻辑运算符会生成到查询条件中,只有OR分组会生成括号。
+ True:按照新的模式,所有的逻辑运算符都会生成到查询条件中,所有分组(AND或OR)都会生成括号。
+
+
属性名:Name
@@ -5810,6 +5904,28 @@
对象池
+
+
+ 动态构建Class Type
+
+
+
+
+
+ 根据字典,创建 table 对应的实体对象
+
+
+
+
+
+
+
+ 根据实体对象,创建 table 对应的字典
+
+
+
+
+
C#: that >= between && that <= and
@@ -5831,6 +5947,36 @@
+
+
+ field IN (value1)
+
+
+
+
+ field in (value1, value2)
+
+
+
+
+ field in (value1, value2, value3)
+
+
+
+
+ field in (value1, value2, value3, value4)
+
+
+
+
+ field in (value1, value2, value3, value4, value5)
+
+
+
+
+ field in (values)
+
+
获取 Type 的原始 c# 文本表示
@@ -6346,126 +6492,3 @@
-
-
-
-
- 插入数据,传入实体集合
-
-
-
-
-
-
-
- 插入数据,传入实体集合
-
-
-
-
-
-
-
- 插入或更新数据,此功能依赖数据库特性(低版本可能不支持),参考如下:
- MySql 5.6+: on duplicate key update
- PostgreSQL 9.4+: on conflict do update
- SqlServer 2008+: merge into
- Oracle 11+: merge into
- Sqlite: replace into
- DuckDB: on conflict do update
- 达梦: merge into
- 人大金仓:on conflict do update
- 神通:merge into
- MsAccess:不支持
- 注意区别:FreeSql.Repository 仓储也有 InsertOrUpdate 方法(不依赖数据库特性)
-
-
-
-
-
-
- 修改数据
-
-
-
-
-
-
- 修改数据,传入动态条件,如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}
-
-
- 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合
-
-
-
-
- 查询数据
-
-
-
-
-
-
- 查询数据,传入动态条件,如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}
-
-
- 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合
-
-
-
-
- 删除数据
-
-
-
-
-
-
- 删除数据,传入动态条件,如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}
-
-
- 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合
-
-
-
-
- 开启事务(不支持异步)
- v1.5.0 关闭了线程事务超时自动提交的机制
-
- 事务体 () => {}
-
-
-
- 开启事务(不支持异步)
- v1.5.0 关闭了线程事务超时自动提交的机制
-
-
- 事务体 () => {}
-
-
-
- 数据库访问对象
-
-
-
-
- 所有拦截方法都在这里
-
-
-
-
- CodeFirst 模式开发相关方法
-
-
-
-
- DbFirst 模式开发相关方法
-
-
-
-
- 全局过滤设置,可默认附加为 Select/Update/Delete 条件
-
-
-
-
diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs
index 1d65a44ca..a81d5c9f1 100644
--- a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs
+++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs
@@ -60,7 +60,8 @@ public Select0Provider()
_paramsInit = _params;
}
- int _disposeCounter;
+ private int _disposeCounter;
+
~Select0Provider()
{
if (Interlocked.Increment(ref _disposeCounter) != 1) return;
@@ -83,6 +84,7 @@ public Select0Provider()
}
public abstract string ToSqlBase(string field = null);
+
public abstract void AsTableBase(Func tableRule);
public static void CopyData(Select0Provider from, Select0Provider to, ReadOnlyCollection lambParms)
@@ -163,6 +165,7 @@ internal class WithTempQueryParser : BaseDiyMemberExpression
{
public List _insideSelectList = new List();
public List _outsideTable = new List();
+
public WithTempQueryParser(Select0Provider insideSelect, SelectGroupingProvider insideSelectGroup, Expression selector, SelectTableInfo outsideTable)
{
if (selector != null)
@@ -171,6 +174,7 @@ public WithTempQueryParser(Select0Provider insideSelect, SelectGroupingProvider
_outsideTable.Add(outsideTable);
}
}
+
public class InsideInfo
{
public Select0Provider InsideSelect { get; }
@@ -238,6 +242,7 @@ public WithTempQueryParser Append(Select0Provider select, SelectTableInfo outsid
}
public SelectTableInfo ParseExpMatchedTable { get; private set; }
+
public override string ParseExp(Expression[] members)
{
ParseExpMapResult = null;
@@ -270,6 +275,7 @@ public override string ParseExp(Expression[] members)
ParseExpMapResult = read;
return $"{ParseExpMatchedTable.Alias}.{read.DbNestedField}";
}
+
public SelectTableInfo GetOutsideSelectTable(ParameterExpression parameterExp)
{
if (parameterExp == null) return null;
@@ -285,6 +291,7 @@ public SelectTableInfo GetOutsideSelectTable(ParameterExpression parameterExp)
public static MethodInfo _methodSqlExtInternalRawField = typeof(SqlExt).GetMethod("InternalRawField", BindingFlags.NonPublic | BindingFlags.Static);
public static MethodInfo _methodSqlExtInternalRawSql = typeof(SqlExt).GetMethod("InternalRawSql", BindingFlags.NonPublic | BindingFlags.Static);
+
public Expression ConvertStringPropertyToExpression(string property, bool fromFirstTable = false)
{
if (string.IsNullOrEmpty(property)) return null;
@@ -343,6 +350,7 @@ public Expression ConvertStringPropertyToExpression(string property, bool fromFi
}
public static MethodInfo _MethodDataReaderIsDBNull = typeof(DbDataReader).GetMethod("IsDBNull", new Type[] { typeof(int) });
+
public static Dictionary _dicMethodDataReaderGetValue = new Dictionary
{
[typeof(bool)] = typeof(DbDataReader).GetMethod("GetBoolean", new Type[] { typeof(int) }),
@@ -355,12 +363,14 @@ public Expression ConvertStringPropertyToExpression(string property, bool fromFi
[typeof(string)] = typeof(DbDataReader).GetMethod("GetString", new Type[] { typeof(int) }),
//[typeof(Guid)] = typeof(DbDataReader).GetMethod("GetGuid", new Type[] { typeof(int) }) 有些驱动不兼容
};
+
public static Dictionary> _dicMethodDataReaderGetValueOverride = new Dictionary>();
public static MethodInfo MethodStringContains = typeof(string).GetMethod("Contains", new[] { typeof(string) });
public static MethodInfo MethodStringStartsWith = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
public static MethodInfo MethodStringEndsWith = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });
- static ConcurrentDictionary MethodEnumerableDic = new ConcurrentDictionary();
+ private static ConcurrentDictionary MethodEnumerableDic = new ConcurrentDictionary();
+
public static MethodInfo GetMethodEnumerable(string methodName) => MethodEnumerableDic.GetOrAdd(methodName, et =>
{
var methods = typeof(Enumerable).GetMethods().Where(a => a.Name == et);
@@ -370,6 +380,7 @@ public static MethodInfo GetMethodEnumerable(string methodName) => MethodEnumera
});
public List> _SameSelectPendingShareData;
+
internal Select0Provider SetSameSelectPendingShareData(List> data)
{
_SameSelectPendingShareData = data;
@@ -383,6 +394,7 @@ internal Select0Provider SetSameSelectPendingShareData(List> data)
{
var callExp = exp as MethodCallExpression;
@@ -449,6 +462,7 @@ public ReadAnonymousTypeAfInfo GetExpressionField(Expression newexp, FieldAliasO
_commonExpression.ReadAnonymousField(_tables, _tableRule, field, map, ref index, newexp, this, _diymemexpWithTempQuery, _whereGlobalFilter, null, null, true);
return new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null);
}
+
public string GetNestSelectSql(Expression select, string affield, Func ToSql)
{
var allMemExps = new FindAllMemberExpressionVisitor(this);
@@ -481,10 +495,12 @@ public string GetNestSelectSql(Expression select, string affield, Func> Result { get; set; } = new List>();
- Select0Provider _select;
+ private Select0Provider _select;
+
public FindAllMemberExpressionVisitor(Select0Provider select) => _select = select;
protected override Expression VisitMember(MemberExpression node)
@@ -535,10 +551,12 @@ protected override Expression VisitMember(MemberExpression node)
return base.VisitMember(node);
}
}
+
public class ReplaceMemberExpressionVisitor : ExpressionVisitor
{
- Expression _findExp;
- Expression _replaceExp;
+ private Expression _findExp;
+ private Expression _replaceExp;
+
public Expression Replace(Expression exp, Expression find, Expression replace) // object repval)
{
_findExp = find;
@@ -546,6 +564,7 @@ public Expression Replace(Expression exp, Expression find, Expression replace) /
//_replaceExp = Expression.Constant(repval, find.Type);
return this.Visit(exp);
}
+
protected override Expression VisitMember(MemberExpression node)
{
if (_findExp == node) return _replaceExp;
@@ -586,17 +605,20 @@ public TSelect WithTransaction(DbTransaction transaction)
if (transaction != null) _connection = transaction.Connection;
return this as TSelect;
}
+
public TSelect WithConnection(DbConnection connection)
{
if (_transaction?.Connection != connection) _transaction = null;
_connection = connection;
return this as TSelect;
}
+
public TSelect WithParameters(List parameters)
{
if (parameters != null) _params = parameters;
return this as TSelect;
}
+
public TSelect CommandTimeout(int timeout)
{
_commandTimeout = timeout;
@@ -611,6 +633,7 @@ public TSelect GroupBy(string sql, object parms = null)
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(_groupby, parms));
return this as TSelect;
}
+
public TSelect Having(string sql, object parms = null)
{
if (string.IsNullOrEmpty(_groupby) || string.IsNullOrEmpty(sql)) return this as TSelect;
@@ -625,18 +648,21 @@ public TSelect LeftJoin(Expression> exp)
_tables[0].Parameter = exp.Parameters[0];
return this.InternalJoin(exp?.Body, SelectTableInfoType.LeftJoin);
}
+
public TSelect InnerJoin(Expression> exp)
{
if (exp == null) return this as TSelect;
_tables[0].Parameter = exp.Parameters[0];
return this.InternalJoin(exp?.Body, SelectTableInfoType.InnerJoin);
}
+
public TSelect RightJoin(Expression> exp)
{
if (exp == null) return this as TSelect;
_tables[0].Parameter = exp.Parameters[0];
return this.InternalJoin(exp?.Body, SelectTableInfoType.RightJoin);
}
+
public TSelect LeftJoin(Expression> exp)
{
if (exp == null) return this as TSelect;
@@ -644,6 +670,7 @@ public TSelect LeftJoin(Expression> exp)
if (_tables.Count > 1 && _tables[1].Table.Type == typeof(T2)) _tables[1].Parameter = exp.Parameters[1];
return this.InternalJoin(exp?.Body, SelectTableInfoType.LeftJoin);
}
+
public TSelect InnerJoin(Expression> exp)
{
if (exp == null) return this as TSelect;
@@ -651,6 +678,7 @@ public TSelect InnerJoin(Expression> exp)
if (_tables.Count > 1 && _tables[1].Table.Type == typeof(T2)) _tables[1].Parameter = exp.Parameters[1];
return this.InternalJoin(exp?.Body, SelectTableInfoType.InnerJoin);
}
+
public TSelect RightJoin(Expression> exp)
{
if (exp == null) return this as TSelect;
@@ -666,6 +694,7 @@ public TSelect InnerJoin(string sql, object parms = null)
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
return this as TSelect;
}
+
public TSelect LeftJoin(string sql, object parms = null)
{
if (string.IsNullOrEmpty(sql)) return this as TSelect;
@@ -673,6 +702,7 @@ public TSelect LeftJoin(string sql, object parms = null)
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
return this as TSelect;
}
+
public TSelect RightJoin(string sql, object parms = null)
{
if (string.IsNullOrEmpty(sql)) return this as TSelect;
@@ -680,6 +710,7 @@ public TSelect RightJoin(string sql, object parms = null)
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
return this as TSelect;
}
+
public TSelect RawJoin(string sql)
{
if (string.IsNullOrEmpty(sql)) return this as TSelect;
@@ -700,14 +731,17 @@ public TSelect Limit(int limit)
_limit = limit;
return this as TSelect;
}
+
public TSelect Master()
{
_select = $" {_select.Trim()} ";
return this as TSelect;
}
+
public TSelect Offset(int offset) => this.Skip(offset) as TSelect;
public TSelect OrderBy(string sql, object parms = null) => this.OrderBy(true, sql, parms);
+
public TSelect OrderBy(bool condition, string sql, object parms = null)
{
if (condition == false) return this as TSelect;
@@ -721,6 +755,7 @@ public TSelect OrderBy(bool condition, string sql, object parms = null)
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
return this as TSelect;
}
+
public TSelect Page(int pageNumber, int pageSize)
{
this.Skip(Math.Max(0, pageNumber - 1) * pageSize);
@@ -739,6 +774,7 @@ public TSelect Skip(int offset)
_skip = offset;
return this as TSelect;
}
+
public TSelect Take(int limit) => this.Limit(limit) as TSelect;
public TSelect Distinct()
@@ -747,7 +783,7 @@ public TSelect Distinct()
return this as TSelect;
}
- string GetToDeleteWhere(string alias)
+ private string GetToDeleteWhere(string alias)
{
var pks = _tables[0].Table.Primarys;
var old_selectVal = _select;
@@ -760,6 +796,7 @@ string GetToDeleteWhere(string alias)
case DataType.Firebird:
case DataType.GBase:
break;
+
default:
_select = "SELECT ";
break;
@@ -794,6 +831,7 @@ string GetToDeleteWhere(string alias)
_select = old_selectVal;
}
}
+
public IDelete ToDelete()
{
if (_tables[0].Table.Primarys.Any() == false) throw new Exception(CoreErrorStrings.Entity_Must_Primary_Key("ToDelete", _tables[0].Table.CsName));
@@ -816,6 +854,7 @@ public IDelete ToDelete()
case DataType.Firebird:
case DataType.GBase:
break;
+
default:
var beforeSql = this._select;
if (beforeSql.EndsWith("SELECT ", StringComparison.OrdinalIgnoreCase))
@@ -828,6 +867,7 @@ public IDelete ToDelete()
}
return del.Where(GetToDeleteWhere("ftb_del"));
}
+
public IUpdate ToUpdate()
{
if (_tables[0].Table.Primarys.Any() == false) throw new Exception(CoreErrorStrings.Entity_Must_Primary_Key("ToUpdate", _tables[0].Table.CsName));
@@ -850,6 +890,7 @@ public IUpdate ToUpdate()
case DataType.Firebird:
case DataType.GBase:
break;
+
default:
var beforeSql = this._select;
if (beforeSql.EndsWith("SELECT ", StringComparison.OrdinalIgnoreCase))
@@ -993,7 +1034,9 @@ string[] LocalGetTableNames(SelectTableInfo tb)
}
return unions;
}
+
public override void AsTableBase(Func tableRule) => AsTable(tableRule);
+
public TSelect AsTable(Func tableRule)
{
if (_tableRules.Count == 1 && _diymemexpWithTempQuery != null && _diymemexpWithTempQuery is WithTempQueryParser tempQueryParser)
@@ -1011,11 +1054,13 @@ public TSelect AsTable(Func tableRule)
if (tableRule != null) _tableRules.Add(tableRule);
return this as TSelect;
}
+
public TSelect AsAlias(Func aliasRule)
{
if (aliasRule != null) _aliasRule = aliasRule;
return this as TSelect;
}
+
public TSelect AsType(Type entityType)
{
if (entityType == typeof(object)) throw new Exception(CoreErrorStrings.TypeAsType_NotSupport_Object("ISelect"));
@@ -1025,10 +1070,13 @@ public TSelect AsType(Type entityType)
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(entityType);
return this as TSelect;
}
+
public override string ToSqlBase(string field = null) => ToSql(field);
+
public abstract string ToSql(string field = null);
public TSelect Where(string sql, object parms = null) => this.WhereIf(true, sql, parms);
+
public TSelect WhereIf(bool condition, string sql, object parms = null)
{
if (condition == false || string.IsNullOrEmpty(sql)) return this as TSelect;
@@ -1038,6 +1086,7 @@ public TSelect WhereIf(bool condition, string sql, object parms = null)
}
public TSelect OrderByPropertyName(string property, bool isAscending = true) => OrderByPropertyNameIf(true, property, isAscending);
+
public TSelect OrderByPropertyNameIf(bool condition, string property, bool isAscending = true)
{
if (condition == false) return this as TSelect;
@@ -1053,13 +1102,30 @@ public TSelect WhereDynamicFilter(DynamicFilterInfo filter)
if (filter == null) return this as TSelect;
var sb = new StringBuilder();
if (IsIgnoreFilter(filter)) filter.Field = "";
+
+ //使用新模式的判断条件,只在第一个过滤器设置即可
+ bool useAllLogic = filter.UseAllLogic;
ParseFilter(DynamicFilterLogic.And, filter, true);
+
+ //新模式下替换可能与括号连在一起的逻辑运算符
+ if (useAllLogic)
+ {
+ sb = sb.Replace("( AND", "(")
+ .Replace("( OR", "(");
+ }
+
this.Where(sb.ToString());
sb.Clear();
return this as TSelect;
void ParseFilter(DynamicFilterLogic logic, DynamicFilterInfo fi, bool isend)
{
+ //新模式下使用过滤器自身的逻辑运算符
+ if (useAllLogic)
+ {
+ logic = fi.Logic;
+ }
+
if (string.IsNullOrEmpty(fi.Field) == false)
{
Expression exp = null;
@@ -1092,6 +1158,7 @@ void ParseFilter(DynamicFilterLogic logic, DynamicFilterInfo fi, bool isend)
exp = ConvertStringPropertyToExpression(fi.Field);
if (exp.Type != typeof(string)) exp = Expression.TypeAs(exp, typeof(string));
break;
+
default:
exp = ConvertStringPropertyToExpression(fi.Field);
if (exp.Type == typeof(object) && fi.Value != null)
@@ -1127,10 +1194,13 @@ void ParseFilter(DynamicFilterLogic logic, DynamicFilterInfo fi, bool isend)
case DynamicFilterOperator.Range:
var fiValueRangeArray = getFiListValue();
if (fiValueRangeArray.Length != 2) throw new ArgumentException(CoreErrorStrings.Range_Comma_Separateda_By2Char);
+
exp = Expression.AndAlso(
- Expression.GreaterThanOrEqual(exp, Expression.Constant(Utils.GetDataReaderValue(exp.Type, fiValueRangeArray[0]), exp.Type)),
- Expression.LessThan(exp, Expression.Constant(Utils.GetDataReaderValue(exp.Type, fiValueRangeArray[1]), exp.Type)));
+ Expression.GreaterThanOrEqual(exp, Expression.Constant(Utils.GetDataReaderValue(exp.Type, fiValueRangeArray[0]), exp.Type)),
+ Expression.LessThan(exp, Expression.Constant(Utils.GetDataReaderValue(exp.Type, fiValueRangeArray[1]), exp.Type)));
+
break;
+
case DynamicFilterOperator.DateRange:
var fiValueDateRangeArray = getFiListValue();
if (fiValueDateRangeArray?.Length != 2) throw new ArgumentException(CoreErrorStrings.DateRange_Comma_Separateda_By2Char);
@@ -1149,7 +1219,9 @@ void ParseFilter(DynamicFilterLogic logic, DynamicFilterInfo fi, bool isend)
exp = Expression.AndAlso(
Expression.GreaterThanOrEqual(exp, Expression.Constant(Utils.GetDataReaderValue(exp.Type, fiValueDateRangeArray[0]), exp.Type)),
Expression.LessThan(exp, Expression.Constant(Utils.GetDataReaderValue(exp.Type, fiValueDateRangeArray[1]), exp.Type)));
+
break;
+
case DynamicFilterOperator.Any:
case DynamicFilterOperator.NotAny:
var fiValueAnyArray = getFiListValue();
@@ -1198,6 +1270,10 @@ string[] getFiListValue()
}
var sql = _commonExpression.ExpressionWhereLambda(_tables, _tableRule, exp, _diymemexpWithTempQuery, null, _params);
+ if (useAllLogic)
+ {
+ sql = " " + fi.Logic.ToString().ToUpper() + " " + sql;
+ }
sb.Append(sql);
}
@@ -1207,16 +1283,33 @@ string[] getFiListValue()
if (fi.Filters.Any())
{
- 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 (useAllLogic)
+ {
+ //第一个条件不用添加逻辑运算符
+ if (fi != filter)
+ {
+ sb.Append(" " + fi.Logic.ToString().ToUpper() + " ");
+ }
+ sb.Append("(");
+ for (var x = 0; x < fi.Filters.Count; x++)
+ ParseFilter(fi.Logic, fi.Filters[x], x == fi.Filters.Count - 1);
+ sb.Append(")");
+ }
+ else
+ {
+ 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 (isend == false && useAllLogic == false)
{
if (string.IsNullOrEmpty(fi.Field) == false || fi.Filters?.Any() == true)
{
@@ -1236,8 +1329,10 @@ bool IsIgnoreFilter(DynamicFilterInfo testFilter)
string.IsNullOrEmpty(testFilter.Value?.ToString());
}
}
- static ConcurrentDictionary _dicMethodIsDynamicFilterCustomAttribute = new ConcurrentDictionary();
- static bool MethodIsDynamicFilterCustomAttribute(MethodInfo method) => _dicMethodIsDynamicFilterCustomAttribute.GetOrAdd(method, m =>
+
+ private static ConcurrentDictionary _dicMethodIsDynamicFilterCustomAttribute = new ConcurrentDictionary();
+
+ private static bool MethodIsDynamicFilterCustomAttribute(MethodInfo method) => _dicMethodIsDynamicFilterCustomAttribute.GetOrAdd(method, m =>
{
object[] attrs = null;
try
@@ -1270,6 +1365,7 @@ public TSelect DisableGlobalFilter(params string[] name)
}
return this as TSelect;
}
+
public TSelect ForUpdate(bool noawait = false)
{
if (_transaction == null && _orm.Ado.TransactionCurrentThread != null) this.WithTransaction(_orm.Ado.TransactionCurrentThread);
@@ -1282,29 +1378,35 @@ public TSelect ForUpdate(bool noawait = false)
case DataType.CustomMySql:
_tosqlAppendContent = $"{_tosqlAppendContent} for update";
break;
+
case DataType.SqlServer:
case DataType.OdbcSqlServer:
case DataType.CustomSqlServer:
_aliasRule = (_, old) => $"{old} With(UpdLock, RowLock{(noawait ? ", NoWait" : "")})";
break;
+
case DataType.PostgreSQL:
case DataType.OdbcPostgreSQL:
case DataType.CustomPostgreSQL:
case DataType.KingbaseES:
_tosqlAppendContent = $"{_tosqlAppendContent} for update{(noawait ? " nowait" : "")}";
break;
+
case DataType.Oracle:
case DataType.OdbcOracle:
case DataType.CustomOracle:
case DataType.Dameng:
_tosqlAppendContent = $"{_tosqlAppendContent} for update{(noawait ? " nowait" : "")}";
break;
+
case DataType.Sqlite:
break;
+
case DataType.GBase:
case DataType.ShenTong: //神通测试中发现,不支持 nowait
_tosqlAppendContent = $"{_tosqlAppendContent} for update";
break;
+
case DataType.Firebird:
_tosqlAppendContent = $"{_tosqlAppendContent} for update with lock";
break;
@@ -1346,6 +1448,7 @@ public bool Any()
this.Limit(1);
return this.ToList($"{1}{_commonUtils.FieldAsAlias("as1")}").Sum() > 0; //这里的 Sum 为了分表查询
}
+
public long Count()
{
var tmpOrderBy = _orderby;
@@ -1370,12 +1473,15 @@ public long Count()
_distinct = tmpDistinct;
}
}
+
public TSelect Count(out long count)
{
count = this.Count();
return this as TSelect;
}
+
public List ToList() => ToList(false);
+
public virtual List ToList(bool includeNestedMembers)
{
if (_diymemexpWithTempQuery != null && _diymemexpWithTempQuery is WithTempQueryParser withTempQueryParser)
@@ -1395,21 +1501,25 @@ public virtual List ToList(bool includeNestedMembers)
if (_selectExpression != null) return this.InternalToList(_selectExpression);
return this.ToListPrivate(includeNestedMembers == false ? this.GetAllFieldExpressionTreeLevel2() : this.GetAllFieldExpressionTreeLevelAll(), null);
}
+
public T1 ToOne()
{
this.Limit(1);
return this.ToList().FirstOrDefault();
}
+
public T1 First() => this.ToOne();
#if net40
#else
- async public Task AnyAsync(CancellationToken cancellationToken = default)
+
+ public async Task AnyAsync(CancellationToken cancellationToken = default)
{
this.Limit(1);
return (await this.ToListAsync($"1{_commonUtils.FieldAsAlias("as1")}", cancellationToken)).Sum() > 0; //这里的 Sum 为了分表查询
}
- async public Task CountAsync(CancellationToken cancellationToken = default)
+
+ public async Task CountAsync(CancellationToken cancellationToken = default)
{
var tmpOrderBy = _orderby;
var tmpSkip = _skip;
@@ -1433,7 +1543,9 @@ async public Task CountAsync(CancellationToken cancellationToken = default
_distinct = tmpDistinct;
}
}
+
public Task> ToListAsync(CancellationToken cancellationToken = default) => ToListAsync(false, cancellationToken);
+
public virtual Task> ToListAsync(bool includeNestedMembers = false, CancellationToken cancellationToken = default)
{
if (_diymemexpWithTempQuery != null && _diymemexpWithTempQuery is WithTempQueryParser withTempQueryParser)
@@ -1453,12 +1565,15 @@ public virtual Task> ToListAsync(bool includeNestedMembers = false, Can
if (_selectExpression != null) return this.InternalToListAsync(_selectExpression, cancellationToken);
return this.ToListPrivateAsync(includeNestedMembers == false ? this.GetAllFieldExpressionTreeLevel2() : this.GetAllFieldExpressionTreeLevelAll(), null, cancellationToken);
}
- async public Task ToOneAsync(CancellationToken cancellationToken = default)
+
+ public async Task ToOneAsync(CancellationToken cancellationToken = default)
{
this.Limit(1);
return (await this.ToListAsync(false, cancellationToken)).FirstOrDefault();
}
+
public Task FirstAsync(CancellationToken cancellationToken = default) => this.ToOneAsync(cancellationToken);
+
#endif
}
}
\ No newline at end of file
diff --git a/FreeSql/Internal/Model/DynamicFilterInfo.cs b/FreeSql/Internal/Model/DynamicFilterInfo.cs
index 6e682207e..1cbb2a345 100644
--- a/FreeSql/Internal/Model/DynamicFilterInfo.cs
+++ b/FreeSql/Internal/Model/DynamicFilterInfo.cs
@@ -16,16 +16,25 @@ namespace FreeSql.Internal.Model
[Serializable]
public class DynamicFilterInfo
{
+ ///
+ /// 使用所有逻辑运算符,默认为False。
+ /// False:按照原来的模式,只有分组的逻辑运算符会生成到查询条件中,只有OR分组会生成括号。
+ /// True:按照新的模式,所有的逻辑运算符都会生成到查询条件中,所有分组(AND或OR)都会生成括号。
+ ///
+ public bool UseAllLogic { get; set; }
+
///
/// 属性名:Name
/// 导航属性:Parent.Name
/// 多表:b.Name
///
public string Field { get; set; }
+
///
/// 操作符
///
public DynamicFilterOperator Operator { get; set; }
+
///
/// 值
///
@@ -35,6 +44,7 @@ public class DynamicFilterInfo
/// Filters 下的逻辑运算符
///
public DynamicFilterLogic Logic { get; set; }
+
///
/// 子过滤条件,它与当前的逻辑关系是 And
/// 注意:当前 Field 可以留空
@@ -42,13 +52,16 @@ public class DynamicFilterInfo
public List Filters { get; set; }
}
- public enum DynamicFilterLogic { And, Or }
+ public enum DynamicFilterLogic
+ { And, Or }
+
public enum DynamicFilterOperator
{
///
/// like
///
Contains,
+
StartsWith,
EndsWith,
NotContains,
@@ -60,16 +73,19 @@ public enum DynamicFilterOperator
/// Equal/Equals/Eq 效果相同
///
Equal,
+
///
/// =
/// Equal/Equals/Eq 效果相同
///
Equals,
+
///
/// =
/// Equal/Equals/Eq 效果相同
///
Eq,
+
///
/// <>
///
@@ -79,14 +95,17 @@ public enum DynamicFilterOperator
/// >
///
GreaterThan,
+
///
/// >=
///
GreaterThanOrEqual,
+
///
/// <
///
LessThan,
+
///
/// <=
///
@@ -116,6 +135,7 @@ public enum DynamicFilterOperator
/// 此时 Value 的值格式为逗号分割:value1,value2,value3... 或者数组
///
Any,
+
///
/// not in (1,2,3)
/// 此时 Value 的值格式为逗号分割:value1,value2,value3... 或者数组
@@ -143,5 +163,6 @@ public enum DynamicFilterOperator
/// 授权 DynamicFilter 支持 Custom 自定义解析
///
[AttributeUsage(AttributeTargets.Method)]
- public class DynamicFilterCustomAttribute : Attribute { }
-}
+ public class DynamicFilterCustomAttribute : Attribute
+ { }
+}
\ No newline at end of file