- 增加 ISelect`1 AsQueryable 方法,实现将 ISelect 转换为 IQueryable 类型;

This commit is contained in:
28810 2020-03-11 18:51:56 +08:00
parent a1a265fa28
commit fff7925d22
7 changed files with 158 additions and 7 deletions

View File

@ -110,13 +110,6 @@
清空状态数据
</summary>
</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)">
<summary>
添加

View File

@ -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<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 list = g.sqlite.Select<Menu, SubSystem>()
.LeftJoin((a,b) => a.SubNameID == b.Id)

View File

@ -1719,6 +1719,14 @@
<param name="sql">SQL语句</param>
<returns></returns>
</member>
<member name="M:FreeSql.ISelect`1.AsQueryable">
<summary>
将 ISelect&lt;T1&gt; 转换为 IQueryable&lt;T1&gt;<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}})">
<summary>
查询条件Where(a => a.Id > 10)支持导航对象查询Where(a => a.Author.Email == "2881099@qq.com")

View File

@ -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
/// <param name="sql">SQL语句</param>
/// <returns></returns>
ISelect<T1> WithSql(string sql);
/// <summary>
/// 将 ISelect&lt;T1&gt; 转换为 IQueryable&lt;T1&gt;<para></para>
/// 此方法主要用于扩展比如abp IRepository GetAll() 接口方法需要返回 IQueryable 对象<para></para>
/// 注意IQueryable 方法污染较为严重,请尽量避免此转换
/// </summary>
/// <returns></returns>
IQueryable<T1> AsQueryable();
}
}

View File

@ -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<Expression>();
@ -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;

View File

@ -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();
}
}

View File

@ -1071,6 +1071,8 @@ namespace FreeSql.Internal.CommonProvider
_trackToList?.Invoke(list);
}
public IQueryable<T1> AsQueryable() => new QueryableProvider<T1>(this);
#if net40
#else
async internal Task SetListAsync(IEnumerable<T1> list)