Merge main branches

This commit is contained in:
igeekfan
2022-05-20 03:16:13 +08:00
121 changed files with 1110 additions and 709 deletions

View File

@ -206,36 +206,24 @@ namespace FreeSql.DataAnnotations
{
return _dicRegSqlWhereDateTimes.GetOrAdd($"{columnName},{quoteParameterName}", cn =>
{
cn = columnName.Replace("[", "\\[").Replace("]", "\\]").Replace(".", "\\.");
cn = columnName.Replace("[", "\\[").Replace("]", "\\]").Replace(".", "\\.").Replace("?", "\\?");
var qpn = quoteParameterName.Replace("[", "\\[").Replace("]", "\\]").Replace(".", "\\.").Replace("?", "\\?");
return new[]
{
//new Regex($@"({cn}\s*(<|<=|>|>=|=|between)\s*)(datetime|cdate|to_date)\(('[^']+')\)", RegexOptions.IgnoreCase),
//new Regex($@"({cn}\s*(<|<=|>|>=|=|between)(\s*))to_timestamp\(('[^']+')\s*,\s*'YYYY-MM-DD[^']+'\)", RegexOptions.IgnoreCase),
//new Regex($@"({cn}\s*(<|<=|>|>=|=|between)(\s*))cast\(('[^']+') as (datetime|timestamp)\)", RegexOptions.IgnoreCase),
//new Regex($@"({cn}\s*(<|<=|>|>=|=|between)(\s*))('[^']+')::(datetime|timestamp)", RegexOptions.IgnoreCase),
//new Regex($@"({cn}\s*(between)\s+'[^']+'\s+and\s+)(datetime|cdate|to_date)\(('[^']+')\)", RegexOptions.IgnoreCase),
//new Regex($@"({cn}\s*(between)\s+'[^']+'\s+and(\s+))to_timestamp\(('[^']+')\s*,\s*'YYYY-MM-DD[^']+'\)", RegexOptions.IgnoreCase),
//new Regex($@"({cn}\s*(between)\s+'[^']+'\s+and(\s+))cast\(('[^']+') as (datetime|timestamp)\)", RegexOptions.IgnoreCase),
//new Regex($@"({cn}\s*(between)\s+'[^']+'\s+and(\s+))('[^']+')::(datetime|timestamp)", RegexOptions.IgnoreCase),
new Regex($@"({cn}\s*(<|<=|>|>=|=)\s*)(datetime|cdate|to_date)\(({quoteParameterName}[\w_]+)\)", RegexOptions.IgnoreCase),
new Regex($@"({cn}\s*(<|<=|>|>=|=)(\s*))to_timestamp\(({quoteParameterName}[\w_]+)\s*,\s*'YYYY-MM-DD[^']+'\)", RegexOptions.IgnoreCase),
new Regex($@"({cn}\s*(<|<=|>|>=|=)(\s*))cast\(({quoteParameterName}[^w_]+) as (datetime|timestamp)\)", RegexOptions.IgnoreCase),
new Regex($@"({cn}\s*(<|<=|>|>=|=)(\s*))({quoteParameterName}[^w_]+)::(datetime|timestamp)", RegexOptions.IgnoreCase),
new Regex($@"({cn}\s*(between)\s+{quoteParameterName}[\w_]+\s+and\s+)(datetime|cdate|to_date)\(({quoteParameterName}[\w_]+)\)", RegexOptions.IgnoreCase),
new Regex($@"({cn}\s*(between)\s+{quoteParameterName}[\w_]+\s+and(\s+))to_timestamp\(({quoteParameterName}[\w_]+)\s*,\s*'YYYY-MM-DD[^']+'\)", RegexOptions.IgnoreCase),
new Regex($@"({cn}\s*(between)\s+{quoteParameterName}[\w_]+\s+and(\s+))cast\(({quoteParameterName}[^w_]+) as (datetime|timestamp)\)", RegexOptions.IgnoreCase),
new Regex($@"({cn}\s*(between)\s+{quoteParameterName}[\w_]+\s+and(\s+))({quoteParameterName}[^w_]+)::(datetime|timestamp)", RegexOptions.IgnoreCase),
new Regex($@"(\s*)(datetime|cdate|to_date)(\s*)\(\s*({qpn}[\w_]+)\s*\)", RegexOptions.IgnoreCase),
new Regex($@"(\s*)(to_timestamp)(\s*)\(\s*({qpn}[\w_]+)\s*,\s*{qpn}[\w_]+\s*\)", RegexOptions.IgnoreCase),
new Regex($@"(\s*)(cast)(\s*)\(\s*({qpn}[^w_]+)\s+as\s+(datetime|timestamp)\s*\)", RegexOptions.IgnoreCase),
new Regex($@"({qpn}[^w_]+)(\s*)(::)(\s*)(datetime|timestamp)", RegexOptions.IgnoreCase),
new Regex($@"(\s*)(timestamp)(\s*)({qpn}[\w_]+)", RegexOptions.IgnoreCase), //firebird
new Regex($@"{cn}\s*between\s*'([^']+)'\s*and\s*'([^']+)'", RegexOptions.IgnoreCase), //预留暂时不用
new Regex($@"{cn}\s*between\s*{quoteParameterName}([\w_]+)\s*and\s*{quoteParameterName}([\w_]+)", RegexOptions.IgnoreCase),
new Regex($@"{cn}\s*between\s*{qpn}([\w_]+)\s*and\s*{qpn}([\w_]+)", RegexOptions.IgnoreCase),
new Regex($@"{cn}\s*(<|<=|>|>=)\s*'([^']+)'\s*and\s*{cn}\s*(<|<=|>|>=)\s*'([^']+)'", RegexOptions.IgnoreCase), //预留暂时不用
new Regex($@"{cn}\s*(<|<=|>|>=)\s*{quoteParameterName}([\w_]+)\s*and\s*{cn}\s*(<|<=|>|>=)\s*{quoteParameterName}([\w_]+)", RegexOptions.IgnoreCase),
new Regex($@"{cn}\s*(<|<=|>|>=)\s*{qpn}([\w_]+)\s*and\s*{cn}\s*(<|<=|>|>=)\s*{qpn}([\w_]+)", RegexOptions.IgnoreCase),
new Regex($@"{cn}\s*(<|<=|>|>=)\s*'([^']+)'", RegexOptions.IgnoreCase), //预留暂时不用
new Regex($@"{cn}\s*(<|<=|>|>=)\s*{quoteParameterName}([\w_]+)", RegexOptions.IgnoreCase),
new Regex($@"{cn}\s*(=|<|<=|>|>=)\s*'([^']+)'", RegexOptions.IgnoreCase), //预留暂时不用
new Regex($@"{cn}\s*(=|<|<=|>|>=)\s*{qpn}([\w_]+)", RegexOptions.IgnoreCase),
};
});
}
@ -265,16 +253,16 @@ namespace FreeSql.DataAnnotations
//var tsqlWhere = Utils.ParseSqlWhereLevel1(sqlWhere);
var regs = GetRegSqlWhereDateTimes($"{(string.IsNullOrWhiteSpace(tb.Alias) ? "" : $"{tb.Alias}.")}{commonUtils.QuoteSqlName(tb.Table.AsTableColumn.Attribute.Name)}", quoteParameterName);
for (var a = 0; a < 8; a++) newSqlWhere = regs[a].Replace(newSqlWhere, "$1$4");
for (var a = 0; a < 5; a++) newSqlWhere = regs[a].Replace(newSqlWhere, "$1$4");
//var m = regs[8].Match(newSqlWhere);
//var m = regs[5].Match(newSqlWhere);
//if (m.Success) return GetTableNamesByColumnValueRange(m.Groups[1].Value, m.Groups[2].Value);
//m = m = regs[10].Match(newSqlWhere);
//m = m = regs[7].Match(newSqlWhere);
//if (m.Success) return LocalGetTables(m.Groups[1].Value, m.Groups[3].Value, ParseColumnValue(m.Groups[2].Value), ParseColumnValue(m.Groups[4].Value));
//m = regs[12].Match(newSqlWhere);
//m = regs[9].Match(newSqlWhere);
//if (m.Success) return LocalGetTables2(m.Groups[1].Value, ParseColumnValue(m.Groups[2].Value));
var m = regs[9].Match(newSqlWhere);
var m = regs[6].Match(newSqlWhere);
if (m.Success)
{
var val1 = LocalGetParamValue(m.Groups[1].Value);
@ -282,7 +270,7 @@ namespace FreeSql.DataAnnotations
if (val1 == null || val2 == null) throw new Exception(CoreStrings.Failed_SubTable_FieldValue(sqlWhere));
return GetTableNamesByColumnValueRange(val1, val2);
}
m = regs[11].Match(newSqlWhere);
m = regs[8].Match(newSqlWhere);
if (m.Success)
{
var val1 = LocalGetParamValue(m.Groups[2].Value);
@ -290,7 +278,7 @@ namespace FreeSql.DataAnnotations
if (val1 == null || val2 == null) throw new Exception(CoreStrings.Failed_SubTable_FieldValue(sqlWhere));
return LocalGetTables(m.Groups[1].Value, m.Groups[3].Value, ParseColumnValue(val1), ParseColumnValue(val2));
}
m = regs[13].Match(newSqlWhere);
m = regs[10].Match(newSqlWhere);
if (m.Success)
{
var val1 = LocalGetParamValue(m.Groups[2].Value);
@ -349,6 +337,8 @@ namespace FreeSql.DataAnnotations
{
switch (m.Groups[1].Value)
{
case "=":
return GetTableNamesByColumnValueRange(val1, val1);
case "<":
val1 = val1.AddSeconds(-1);
return GetTableNamesByColumnValueRange(_beginTime, val1);

View File

@ -2609,11 +2609,19 @@
</member>
<member name="M:FreeSql.ISelectGrouping`2.Having(System.Linq.Expressions.Expression{System.Func{FreeSql.ISelectGroupingAggregate{`0,`1},System.Boolean}})">
<summary>
按聚合条件过滤,Where(a => a.Count() > 10)
按聚合条件过滤,Having(a => a.Count() > 10)
</summary>
<param name="exp">lambda表达式</param>
<returns></returns>
</member>
<member name="M:FreeSql.ISelectGrouping`2.HavingIf(System.Boolean,System.Linq.Expressions.Expression{System.Func{FreeSql.ISelectGroupingAggregate{`0,`1},System.Boolean}})">
<summary>
按聚合条件过滤HavingIf(true, a => a.Count() > 10)
</summary>
<param name="condition">true 时生效</param>
<param name="exp">lambda表达式</param>
<returns></returns>
</member>
<member name="M:FreeSql.ISelectGrouping`2.OrderBy``1(System.Linq.Expressions.Expression{System.Func{FreeSql.ISelectGroupingAggregate{`0,`1},``0}})">
<summary>
按列排序OrderBy(a => a.Time)

View File

@ -19,11 +19,18 @@ namespace FreeSql
#endif
/// <summary>
/// 按聚合条件过滤,Where(a => a.Count() > 10)
/// 按聚合条件过滤,Having(a => a.Count() > 10)
/// </summary>
/// <param name="exp">lambda表达式</param>
/// <returns></returns>
ISelectGrouping<TKey, TValue> Having(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, bool>> exp);
/// <summary>
/// 按聚合条件过滤HavingIf(true, a => a.Count() > 10)
/// </summary>
/// <param name="condition">true 时生效</param>
/// <param name="exp">lambda表达式</param>
/// <returns></returns>
ISelectGrouping<TKey, TValue> HavingIf(bool condition, Expression<Func<ISelectGroupingAggregate<TKey, TValue>, bool>> exp);
/// <summary>
/// 按列排序OrderBy(a => a.Time)

View File

@ -760,7 +760,9 @@ namespace FreeSql.Internal
var conditionalTestOldMapType = tsc.SetMapTypeReturnOld(null);
if (condExp.Test.IsParameter())
{
var conditionalTestSql = ExpressionLambdaToSql(condExp.Test, tsc);
var condExp2 = condExp.Test;
if (condExp2.NodeType == ExpressionType.MemberAccess) condExp2 = Expression.Equal(condExp2, Expression.Constant(true));
var conditionalTestSql = ExpressionLambdaToSql(condExp2, tsc);
tsc.SetMapTypeReturnOld(conditionalTestOldMapType);
var conditionalSql = _common.IIF(conditionalTestSql, ExpressionLambdaToSql(condExp.IfTrue, tsc), ExpressionLambdaToSql(condExp.IfFalse, tsc));
tsc.SetMapTypeReturnOld(null);
@ -1265,7 +1267,7 @@ namespace FreeSql.Internal
var sql4 = fsqlType.GetMethod("ToSql", new Type[] { typeof(string) })?.Invoke(fsql, new object[] { $"{exp3.Method.Name.ToLower()}({fieldSql})" })?.ToString();
asSelectBefores.Clear();
return $"({sql4.Replace(" \r\n", " \r\n ")})";
return _common.IsNull($"({sql4.Replace(" \r\n", " \r\n ")})", 0);
}
var sql3 = manySubSelectAggMethod.Invoke(fsql, new object[] { exp3Args0, FieldAliasOptions.AsProperty }) as string;
@ -1320,7 +1322,7 @@ namespace FreeSql.Internal
exp3Args0 = new ReplaceHzyTupleToMultiParam().Modify(exp3Args0, fsqltables);
var sqlSum = fsqlType.GetMethod("ToSql", new Type[] { typeof(string) })?.Invoke(fsql, new object[] { $"{exp3.Method.Name.ToLower()}({ExpressionLambdaToSql(exp3Args0, tscClone1)})" })?.ToString();
if (string.IsNullOrEmpty(sqlSum) == false)
return $"({sqlSum.Replace(" \r\n", " \r\n ")})";
return _common.IsNull($"({sqlSum.Replace(" \r\n", " \r\n ")})", 0);
break;
case "ToList":
case "ToOne":
@ -1965,7 +1967,33 @@ namespace FreeSql.Internal
return;
}
exp3tmp = exp3Stack.Pop();
if (exp3tmp.NodeType != ExpressionType.Parameter) return;
if (exp3tmp.NodeType != ExpressionType.Parameter)
{
//if (e.Expression.NodeType == ExpressionType.Call)
//{
// var rootExpCall = e.Expression as MethodCallExpression;
// if (rootExpCall.Object == null && rootExpCall.Method.Name == "Any" &&
// rootExpCall.Arguments.Count == 2 &&
// rootExpCall.Arguments[0].Type.GetGenericTypeDefinition() == typeof(IEnumerable<>) &&
// rootExpCall.Arguments[1].Type == typeof(Func<,>).MakeGenericType(rootExpCall.Arguments[0].Type.GetGenericArguments()[0], typeof(bool)))
// {
// //e.Tables[0].Parameter
// var anyExp = rootExpCall.Arguments[1];
// while(anyExp.NodeType == ExpressionType.AndAlso)
// {
// }
// if (anyExp.NodeType != ExpressionType.AndAlso && anyExp.NodeType != ExpressionType.Equal) return;
// var array = Expression.Lambda(rootExpCall.Arguments[0]).Compile().DynamicInvoke() as IEnumerable;
// foreach (var arritem in array)
// {
// }
// }
//}
return;
}
if (exp3tmp.Type.FullName.StartsWith("FreeSql.ISelectGroupingAggregate")) return;
var commonExp = sender as FreeSql.Internal.CommonExpression;
if (commonExp == null) return;
@ -2109,7 +2137,7 @@ namespace FreeSql.Internal
commonExp.ReadAnonymousField(select._tables, field, map, ref index, callExp.Arguments[1], null, null, null, null, false);
var fieldSql = field.Length > 0 ? field.Remove(0, 2).ToString() : null;
e.Result = $"({select.ToSql($"{aggregateMethodName}({fieldSql})").Replace(" \r\n", " \r\n ")})";
e.Result = commonExp._common.IsNull($"({select.ToSql($"{aggregateMethodName}({fieldSql})").Replace(" \r\n", " \r\n ")})", 0);
return;
}
throw throwCallExp($"不支持 {callExp.Arguments.Count}个参数的方法");

View File

@ -302,6 +302,11 @@ namespace FreeSql.Internal.CommonProvider
{
if (string.IsNullOrEmpty(sql)) return this as TSelect;
_join.Append(" \r\n").Append(sql);
//fsql.Select<User1, UserGroup>().RawJoin("FULL JOIN UserGroup b ON b.id = a.GroupId").ToSql((a, b) => new { user = a, group = b });
foreach (var tb in _tables)
if (sql.Contains($" {tb.Table.DbName} ") || sql.Contains($" {_commonUtils.QuoteSqlName(tb.Table.DbName)} "))
tb.Type = SelectTableInfoType.RawJoin;
return this as TSelect;
}

View File

@ -993,7 +993,8 @@ namespace FreeSql.Internal.CommonProvider
List<object> midList = new List<object>();
var tbref2 = _commonUtils.GetTableByEntity(tbref.RefEntityType);
var tbrefMid = _commonUtils.GetTableByEntity(tbref.RefMiddleEntityType);
var sbJoin = new StringBuilder().Append($"{_commonUtils.QuoteSqlName(tbrefMid.DbName)} midtb ON ");
var tbrefMidName = _tableRules?.FirstOrDefault()?.Invoke(tbref.RefMiddleEntityType, tbrefMid.DbName) ?? tbrefMid.DbName;
var sbJoin = new StringBuilder().Append($"{_commonUtils.QuoteSqlName(tbrefMidName)} midtb ON ");
for (var z = 0; z < tbref.RefColumns.Count; z++)
{
if (z > 0) sbJoin.Append(" AND ");

View File

@ -226,6 +226,7 @@ namespace FreeSql.Internal.CommonProvider
return this;
}
public ISelectGrouping<TKey, TValue> HavingIf(bool condition, Expression<Func<ISelectGroupingAggregate<TKey, TValue>, bool>> exp) => condition ? Having(exp) : this;
public ISelectGrouping<TKey, TValue> Having(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, bool>> exp)
{
_lambdaParameter = exp?.Parameters[0];

View File

@ -24,5 +24,5 @@ namespace FreeSql.Internal.Model
public string Cascade { get; set; }
}
public enum SelectTableInfoType { From, LeftJoin, InnerJoin, RightJoin, Parent }
public enum SelectTableInfoType { From, LeftJoin, InnerJoin, RightJoin, RawJoin, Parent }
}