mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 10:42:52 +08:00
- 增加 ISelect`1 AsQueryable 方法,实现将 ISelect 转换为 IQueryable 类型;
This commit is contained in:
parent
a1a265fa28
commit
fff7925d22
@ -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>
|
||||
添加
|
||||
|
@ -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)
|
||||
|
@ -1719,6 +1719,14 @@
|
||||
<param name="sql">SQL语句</param>
|
||||
<returns></returns>
|
||||
</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}})">
|
||||
<summary>
|
||||
查询条件,Where(a => a.Id > 10),支持导航对象查询,Where(a => a.Author.Email == "2881099@qq.com")
|
||||
|
@ -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<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 "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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
public IQueryable<T1> AsQueryable() => new QueryableProvider<T1>(this);
|
||||
|
||||
#if net40
|
||||
#else
|
||||
async internal Task SetListAsync(IEnumerable<T1> list)
|
||||
|
Loading…
x
Reference in New Issue
Block a user