diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index 9c6cd88b..743835e4 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -532,5 +532,14 @@ + + + 批量注入 Repository,可以参考代码自行调整 + + + + + + diff --git a/FreeSql.Tests/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs b/FreeSql.Tests/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs index b2d9a63d..3d7caa44 100644 --- a/FreeSql.Tests/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs @@ -2304,6 +2304,67 @@ WHERE ((a.""CreateTime"" >= '2010-10-10 00:00:00' AND a.""CreateTime"" < '2010-1 FROM ""D_District"" a LEFT JOIN ""D_District"" a__Parent ON a__Parent.""Code"" = a.""ParentCode"" WHERE ((not((a.""Code"") LIKE '%val1%') AND not((a.""Name"") LIKE 'val2%') OR not((a.""Name"") LIKE '%val3') OR a.""ParentCode"" <> 'val4' OR a__Parent.""Code"" = 'val11' AND (a__Parent.""Name"") LIKE '%val22%' OR a__Parent.""Name"" = 'val33' OR a__Parent.""ParentCode"" = 'val44'))", sql); + + sql = fsql.Select().OrderByPropertyName("Parent.Name").WhereDynamicFilter(JsonConvert.DeserializeObject(@" +{ + ""Logic"" : ""Or"", + ""Filters"" : + [ + { + ""Field"" : ""Code"", + ""Operator"" : ""NotContains"", + ""Value"" : ""val1"", + ""Filters"" : + [ + { + ""Field"" : ""Name"", + ""Operator"" : ""NotStartsWith"", + ""Value"" : ""val2"", + } + ] + }, + { + ""Field"" : ""Name"", + ""Operator"" : ""NotEndsWith"", + ""Value"" : ""val3"" + }, + { + ""Field"" : ""ParentCode"", + ""Operator"" : ""NotEqual"", + ""Value"" : ""val4"" + }, + + { + ""Field"" : ""Parent.Code"", + ""Operator"" : ""eq"", + ""Value"" : ""val11"", + ""Filters"" : + [ + { + ""Field"" : ""Parent.Name"", + ""Operator"" : ""contains"", + ""Value"" : ""val22"", + } + ] + }, + { + ""Field"" : ""Parent.Name"", + ""Operator"" : ""eq"", + ""Value"" : ""val33"" + }, + { + ""Field"" : ""Parent.ParentCode"", + ""Operator"" : ""eq"", + ""Value"" : ""val44"" + } + ] +} +")).ToSql(); + Assert.Equal(@"SELECT a.""Code"", a.""Name"", a.""CreateTime"", a.""testint"", a.""ParentCode"", a__Parent.""Code"" as6, a__Parent.""Name"" as7, a__Parent.""CreateTime"" as8, a__Parent.""testint"" as9, a__Parent.""ParentCode"" as10 +FROM ""D_District"" a +LEFT JOIN ""D_District"" a__Parent ON a__Parent.""Code"" = a.""ParentCode"" +WHERE ((not((a.""Code"") LIKE '%val1%') AND not((a.""Name"") LIKE 'val2%') OR not((a.""Name"") LIKE '%val3') OR a.""ParentCode"" <> 'val4' OR a__Parent.""Code"" = 'val11' AND (a__Parent.""Name"") LIKE '%val22%' OR a__Parent.""Name"" = 'val33' OR a__Parent.""ParentCode"" = 'val44')) +ORDER BY a__Parent.""Name""", sql); } } } diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index 79039cd6..b99f558c 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -1943,6 +1943,25 @@ 参数 + + + 按属性名字符串排序(支持导航属性) + 属性名:Name导航属性:Parent.Name多表:b.Name + + 属性名:Name导航属性:Parent.Name多表:b.Name + 顺序 | 倒序 + + + + + 按属性名字符串排序(支持导航属性) + 属性名:Name导航属性:Parent.Name多表:b.Name + + true 时生效 + 属性名:Name导航属性:Parent.Name多表:b.Name + 顺序 | 倒序 + + 查询向后偏移行数 diff --git a/FreeSql/Interface/Curd/ISelect/ISelect0.cs b/FreeSql/Interface/Curd/ISelect/ISelect0.cs index 7180b408..4ef554fd 100644 --- a/FreeSql/Interface/Curd/ISelect/ISelect0.cs +++ b/FreeSql/Interface/Curd/ISelect/ISelect0.cs @@ -337,6 +337,23 @@ namespace FreeSql /// 参数 /// TSelect OrderBy(bool condition, string sql, object parms = null); + /// + /// 按属性名字符串排序(支持导航属性) + /// 属性名:Name导航属性:Parent.Name多表:b.Name + /// + /// 属性名:Name导航属性:Parent.Name多表:b.Name + /// 顺序 | 倒序 + /// + TSelect OrderByPropertyName(string property, bool isAscending = true); + /// + /// 按属性名字符串排序(支持导航属性) + /// 属性名:Name导航属性:Parent.Name多表:b.Name + /// + /// true 时生效 + /// 属性名:Name导航属性:Parent.Name多表:b.Name + /// 顺序 | 倒序 + /// + TSelect OrderByPropertyNameIf(bool condition, string property, bool isAscending = true); /// /// 查询向后偏移行数 diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs index 9a67dc82..d8ca14e4 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs @@ -442,6 +442,60 @@ namespace FreeSql.Internal.CommonProvider return this as TSelect; } + public Expression ConvertStringPropertyToExpression(string property) + { + if (string.IsNullOrEmpty(property)) return null; + var field = property.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($"无法匹配 {property}"); + } + 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; + } + return exp; + } + + 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; + Expression exp = ConvertStringPropertyToExpression(property); + if (exp == null) return this as TSelect; + var field = _commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null); + if (isAscending) return this.OrderBy(field); + return this.OrderBy($"{field} DESC"); + } + 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) }); @@ -460,44 +514,7 @@ namespace FreeSql.Internal.CommonProvider { 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; - } - + Expression exp = ConvertStringPropertyToExpression(fi.Field); switch (fi.Operator) { case DynamicFilterOperator.Contains: exp = Expression.Call(exp, MethodStringContains, Expression.Constant(Utils.GetDataReaderValue(exp.Type, fi.Value?.ToString()), exp.Type)); break;