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