mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 01:05:27 +08:00 
			
		
		
		
	- 增加 ISelect`1 AsQueryable 方法,实现将 ISelect 转换为 IQueryable 类型;
This commit is contained in:
		@@ -110,13 +110,6 @@
 | 
				
			|||||||
            清空状态数据
 | 
					            清空状态数据
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:FreeSql.DbSet`1.RemoveAsync(System.Linq.Expressions.Expression{System.Func{`0,System.Boolean}})">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            根据 lambda 条件删除数据
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="predicate"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.DbSet`1.Add(`0)">
 | 
					        <member name="M:FreeSql.DbSet`1.Add(`0)">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            添加
 | 
					            添加
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -116,9 +116,39 @@ namespace FreeSql.Tests
 | 
				
			|||||||
            public string Name { get; set; }
 | 
					            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]
 | 
					        [Fact]
 | 
				
			||||||
        public void Test03()
 | 
					        public void Test03()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            var lksdjkg1 = g.sqlite.Select<Edi>()
 | 
				
			||||||
 | 
					                .AsQueryable().Where(a => a.Id > 0).ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var lksdjkg2 = g.sqlite.Select<Edi>()
 | 
				
			||||||
 | 
					                .AsQueryable().Where(a => a.Id > 0).First();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var lksdjkg3 = g.sqlite.Select<Edi>()
 | 
				
			||||||
 | 
					                .AsQueryable().Where(a => a.Id > 0).FirstOrDefault();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var sql222efe = g.sqlite.Select<Edi, EdiItem>()
 | 
				
			||||||
 | 
					                .InnerJoin((a, b) => b.Id == g.sqlite.Select<EdiItem>().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 subSyetemId = "xxx";
 | 
				
			||||||
            var list = g.sqlite.Select<Menu, SubSystem>()
 | 
					            var list = g.sqlite.Select<Menu, SubSystem>()
 | 
				
			||||||
                .LeftJoin((a,b) => a.SubNameID == b.Id)
 | 
					                .LeftJoin((a,b) => a.SubNameID == b.Id)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1719,6 +1719,14 @@
 | 
				
			|||||||
            <param name="sql">SQL语句</param>
 | 
					            <param name="sql">SQL语句</param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.ISelect`1.AsQueryable">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            将 ISelect<T1> 转换为 IQueryable<T1><para></para>
 | 
				
			||||||
 | 
					            此方法主要用于扩展,比如:abp IRepository GetAll() 接口方法需要返回 IQueryable 对象<para></para>
 | 
				
			||||||
 | 
					            注意:IQueryable 方法污染较为严重,请尽量避免此转换
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
        <member name="M:FreeSql.ISelectFromExpression`1.Where(System.Linq.Expressions.Expression{System.Func{`0,System.Boolean}})">
 | 
					        <member name="M:FreeSql.ISelectFromExpression`1.Where(System.Linq.Expressions.Expression{System.Func{`0,System.Boolean}})">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            查询条件,Where(a => a.Id > 10),支持导航对象查询,Where(a => a.Author.Email == "2881099@qq.com")
 | 
					            查询条件,Where(a => a.Id > 10),支持导航对象查询,Where(a => a.Author.Email == "2881099@qq.com")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -377,5 +378,13 @@ namespace FreeSql
 | 
				
			|||||||
        /// <param name="sql">SQL语句</param>
 | 
					        /// <param name="sql">SQL语句</param>
 | 
				
			||||||
        /// <returns></returns>
 | 
					        /// <returns></returns>
 | 
				
			||||||
        ISelect<T1> WithSql(string sql);
 | 
					        ISelect<T1> WithSql(string sql);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 将 ISelect<T1> 转换为 IQueryable<T1><para></para>
 | 
				
			||||||
 | 
					        /// 此方法主要用于扩展,比如:abp IRepository GetAll() 接口方法需要返回 IQueryable 对象<para></para>
 | 
				
			||||||
 | 
					        /// 注意:IQueryable 方法污染较为严重,请尽量避免此转换
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        IQueryable<T1> AsQueryable();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -707,6 +707,7 @@ namespace FreeSql.Internal
 | 
				
			|||||||
                            case "Max":
 | 
					                            case "Max":
 | 
				
			||||||
                            case "Avg":
 | 
					                            case "Avg":
 | 
				
			||||||
                            case "ToList": //where in
 | 
					                            case "ToList": //where in
 | 
				
			||||||
 | 
					                            case "ToOne":
 | 
				
			||||||
                            case "First":
 | 
					                            case "First":
 | 
				
			||||||
                                var anyArgs = exp3.Arguments;
 | 
					                                var anyArgs = exp3.Arguments;
 | 
				
			||||||
                                var exp3Stack = new Stack<Expression>();
 | 
					                                var exp3Stack = new Stack<Expression>();
 | 
				
			||||||
@@ -991,6 +992,7 @@ namespace FreeSql.Internal
 | 
				
			|||||||
                                                return $"({sqlSum.Replace("\r\n", "\r\n\t")})";
 | 
					                                                return $"({sqlSum.Replace("\r\n", "\r\n\t")})";
 | 
				
			||||||
                                            break;
 | 
					                                            break;
 | 
				
			||||||
                                        case "ToList":
 | 
					                                        case "ToList":
 | 
				
			||||||
 | 
					                                        case "ToOne":
 | 
				
			||||||
                                        case "First":
 | 
					                                        case "First":
 | 
				
			||||||
                                            var tscClone2 = tsc.CloneDisableDiyParse();
 | 
					                                            var tscClone2 = tsc.CloneDisableDiyParse();
 | 
				
			||||||
                                            tscClone2.isDisableDiyParse = false;
 | 
					                                            tscClone2.isDisableDiyParse = false;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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<T> : IQueryable<T>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        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<T>(_select, _commonExpression);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public QueryableProvider(Expression expression, IQueryProvider provider, object select, CommonExpression commonExpression)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _select = select;
 | 
				
			||||||
 | 
					            _commonExpression = commonExpression;
 | 
				
			||||||
 | 
					            _expression = expression;
 | 
				
			||||||
 | 
					            _provider = provider;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IEnumerator<T> GetEnumerator()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var result = _provider.Execute<List<T>>(_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<T>);
 | 
				
			||||||
 | 
					        public Expression Expression => _expression;
 | 
				
			||||||
 | 
					        public IQueryProvider Provider => _provider;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class QueryProvider<T> : IQueryProvider
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private object _select;
 | 
				
			||||||
 | 
					        private CommonExpression _commonExpression;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public QueryProvider(object select, CommonExpression commonExpression)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _select = select;
 | 
				
			||||||
 | 
					            _commonExpression = commonExpression;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            IQueryable<TElement> query = new QueryableProvider<TElement>(expression, this, _select, _commonExpression);
 | 
				
			||||||
 | 
					            return query;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public IQueryable CreateQuery(Expression expression) => throw new NotImplementedException();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public TResult Execute<TResult>(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();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1071,6 +1071,8 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            _trackToList?.Invoke(list);
 | 
					            _trackToList?.Invoke(list);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IQueryable<T1> AsQueryable() => new QueryableProvider<T1>(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if net40
 | 
					#if net40
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
        async internal Task SetListAsync(IEnumerable<T1> list)
 | 
					        async internal Task SetListAsync(IEnumerable<T1> list)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user