diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index ca7c357b..2735cefb 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -110,13 +110,6 @@ 清空状态数据 - - - 根据 lambda 条件删除数据 - - - - 添加 diff --git a/FreeSql.Tests/FreeSql.Tests/UnitTest3.cs b/FreeSql.Tests/FreeSql.Tests/UnitTest3.cs index 49ecb36e..dc3ae2e0 100644 --- a/FreeSql.Tests/FreeSql.Tests/UnitTest3.cs +++ b/FreeSql.Tests/FreeSql.Tests/UnitTest3.cs @@ -116,9 +116,39 @@ namespace FreeSql.Tests public string Name { get; set; } } + [Table(Name = "EDI")] + public class Edi + { + [Column(Name = "EDI_ID")] public long Id { get; set; } + } + [Table(Name = "EDI_ITEM")] + public class EdiItem + { + [Column(Name = "EDII_ID")] public long Id { get; set; } + [Column(Name = "EDII_EDI_ID")] public long EdiId { get; set; } + } + [Fact] public void Test03() { + var lksdjkg1 = g.sqlite.Select() + .AsQueryable().Where(a => a.Id > 0).ToList(); + + var lksdjkg2 = g.sqlite.Select() + .AsQueryable().Where(a => a.Id > 0).First(); + + var lksdjkg3 = g.sqlite.Select() + .AsQueryable().Where(a => a.Id > 0).FirstOrDefault(); + + + var sql222efe = g.sqlite.Select() + .InnerJoin((a, b) => b.Id == g.sqlite.Select().As("c").Where(c => c.EdiId == a.Id).OrderBy(c => c.Id).ToOne(c => c.Id)) + .ToSql((a, b) => new + { + Id = a.Id, + EdiId = b.Id + }); + var subSyetemId = "xxx"; var list = g.sqlite.Select() .LeftJoin((a,b) => a.SubNameID == b.Id) diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index 08d2c1b3..89c147ea 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -1719,6 +1719,14 @@ SQL语句 + + + 将 ISelect<T1> 转换为 IQueryable<T1> + 此方法主要用于扩展,比如:abp IRepository GetAll() 接口方法需要返回 IQueryable 对象 + 注意:IQueryable 方法污染较为严重,请尽量避免此转换 + + + 查询条件,Where(a => a.Id > 10),支持导航对象查询,Where(a => a.Author.Email == "2881099@qq.com") diff --git a/FreeSql/Interface/Curd/ISelect/ISelect1.cs b/FreeSql/Interface/Curd/ISelect/ISelect1.cs index 34c9ce6d..a6bb4622 100644 --- a/FreeSql/Interface/Curd/ISelect/ISelect1.cs +++ b/FreeSql/Interface/Curd/ISelect/ISelect1.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Data; +using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; @@ -377,5 +378,13 @@ namespace FreeSql /// SQL语句 /// ISelect WithSql(string sql); + + /// + /// 将 ISelect<T1> 转换为 IQueryable<T1> + /// 此方法主要用于扩展,比如:abp IRepository GetAll() 接口方法需要返回 IQueryable 对象 + /// 注意:IQueryable 方法污染较为严重,请尽量避免此转换 + /// + /// + IQueryable AsQueryable(); } } \ No newline at end of file diff --git a/FreeSql/Internal/CommonExpression.cs b/FreeSql/Internal/CommonExpression.cs index f9e424d1..2138f213 100644 --- a/FreeSql/Internal/CommonExpression.cs +++ b/FreeSql/Internal/CommonExpression.cs @@ -707,6 +707,7 @@ namespace FreeSql.Internal case "Max": case "Avg": case "ToList": //where in + case "ToOne": case "First": var anyArgs = exp3.Arguments; var exp3Stack = new Stack(); @@ -991,6 +992,7 @@ namespace FreeSql.Internal return $"({sqlSum.Replace("\r\n", "\r\n\t")})"; break; case "ToList": + case "ToOne": case "First": var tscClone2 = tsc.CloneDisableDiyParse(); tscClone2.isDisableDiyParse = false; diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/QueryableProvider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/QueryableProvider.cs new file mode 100644 index 00000000..bf52e097 --- /dev/null +++ b/FreeSql/Internal/CommonProvider/SelectProvider/QueryableProvider.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; + +namespace FreeSql.Internal.CommonProvider +{ + class QueryableProvider : IQueryable + { + private Expression _expression; + private IQueryProvider _provider; + private object _select; + private CommonExpression _commonExpression; + + public QueryableProvider(object select) + { + _select = select; + _commonExpression = _select.GetType().GetField("_commonExpression", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(_select) as CommonExpression; + _expression = Expression.Constant(this); + _provider = new QueryProvider(_select, _commonExpression); + } + public QueryableProvider(Expression expression, IQueryProvider provider, object select, CommonExpression commonExpression) + { + _select = select; + _commonExpression = commonExpression; + _expression = expression; + _provider = provider; + } + + public IEnumerator GetEnumerator() + { + var result = _provider.Execute>(_expression); + if (result == null) + yield break; + foreach (var item in result) + { + yield return item; + } + } + IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); + + public Type ElementType => typeof(QueryableProvider); + public Expression Expression => _expression; + public IQueryProvider Provider => _provider; + } + + class QueryProvider : IQueryProvider + { + private object _select; + private CommonExpression _commonExpression; + + public QueryProvider(object select, CommonExpression commonExpression) + { + _select = select; + _commonExpression = commonExpression; + } + + public IQueryable CreateQuery(Expression expression) + { + IQueryable query = new QueryableProvider(expression, this, _select, _commonExpression); + return query; + } + public IQueryable CreateQuery(Expression expression) => throw new NotImplementedException(); + + + public TResult Execute(Expression expression) + { + var methodExp = expression as MethodCallExpression; + while (methodExp != null) + { + switch (methodExp.Method.Name) + { + case "First": + case "FirstOrDefault": + _select.GetType().GetMethod("Limit", new[] { typeof(int) }).Invoke(_select, new object[] { 1 }); + break; + default: + var selectMethod = _select.GetType().GetMethod(methodExp.Method.Name, methodExp.Arguments.Where((a, b) => b > 0).Select(a => a.Type).ToArray()); + if (selectMethod == null) throw new Exception($"无法找到 ISelect.{methodExp.Method.Name}({string.Join(", ", methodExp.Arguments.Select(a => a.Type.FullName))}) 方法"); + + var selectArgs = methodExp.Arguments.Where((a, b) => b > 0).Select(a => + { + switch (a.NodeType) + { + case ExpressionType.Lambda: return (object)a; + default: return Expression.Lambda(a).Compile().DynamicInvoke(); + } + }).ToArray(); + selectMethod.Invoke(_select, selectArgs); + break; + } + methodExp = methodExp.Arguments.FirstOrDefault() as MethodCallExpression; + } + var resultType = typeof(TResult); + var resultTypeIsList = typeof(IList).IsAssignableFrom(resultType); + if (resultTypeIsList) resultType = resultType.GetGenericArguments()[0]; + var ret = _select.GetType().GetMethod(resultTypeIsList ? "ToList" : "First", new Type[0]) + .MakeGenericMethod(resultType) + .Invoke(_select, new object[0]); + return (TResult)ret; + } + public object Execute(Expression expression) => throw new NotImplementedException(); + } +} diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs index 83cb8b3d..2d3b877f 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs @@ -1071,6 +1071,8 @@ namespace FreeSql.Internal.CommonProvider _trackToList?.Invoke(list); } + public IQueryable AsQueryable() => new QueryableProvider(this); + #if net40 #else async internal Task SetListAsync(IEnumerable list)