mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-06-18 20:08:15 +08:00
- 调整 ISelect linq to sql 和 queryable 实现依赖移至 FreeSql.Extensions.Linq;#260
This commit is contained in:
@ -0,0 +1,37 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;net45;net40</TargetFrameworks>
|
||||
<Version>1.4.0-preview20200410</Version>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Authors>YeXiangQin</Authors>
|
||||
<Description>FreeSql 扩展包,实现 linq queryable 和 linq to sql 语法进行开发.</Description>
|
||||
<PackageProjectUrl>https://github.com/2881099/FreeSql</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/2881099/FreeSql</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageTags>FreeSql;ORM</PackageTags>
|
||||
<PackageId>$(AssemblyName)</PackageId>
|
||||
<PackageIcon>logo.png</PackageIcon>
|
||||
<Title>$(AssemblyName)</Title>
|
||||
<IsPackable>true</IsPackable>
|
||||
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
|
||||
<DelaySign>false</DelaySign>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="../../logo.png" Pack="true" PackagePath="\" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
|
||||
<DocumentationFile>FreeSql.Extensions.Linq.xml</DocumentationFile>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -0,0 +1,41 @@
|
||||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>FreeSql.Extensions.Linq</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="M:FreeSqlExtensionsLinqSql.AsQueryable``1(FreeSql.ISelect{``0})">
|
||||
<summary>
|
||||
将 ISelect<T1> 转换为 IQueryable<T1><para></para>
|
||||
此方法主要用于扩展,比如:abp IRepository GetAll() 接口方法需要返回 IQueryable 对象<para></para>
|
||||
注意:IQueryable 方法污染较为严重,请尽量避免此转换
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:FreeSqlExtensionsLinqSql.Select``2(FreeSql.ISelect{``0},System.Linq.Expressions.Expression{System.Func{``0,``1}})">
|
||||
<summary>
|
||||
【linq to sql】专用扩展方法,不建议直接使用
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:FreeSqlExtensionsLinqSql.Join``4(FreeSql.ISelect{``0},FreeSql.ISelect{``1},System.Linq.Expressions.Expression{System.Func{``0,``2}},System.Linq.Expressions.Expression{System.Func{``1,``2}},System.Linq.Expressions.Expression{System.Func{``0,``1,``3}})">
|
||||
<summary>
|
||||
【linq to sql】专用扩展方法,不建议直接使用
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:FreeSqlExtensionsLinqSql.GroupJoin``4(FreeSql.ISelect{``0},FreeSql.ISelect{``1},System.Linq.Expressions.Expression{System.Func{``0,``2}},System.Linq.Expressions.Expression{System.Func{``1,``2}},System.Linq.Expressions.Expression{System.Func{``0,FreeSql.ISelect{``1},``3}})">
|
||||
<summary>
|
||||
【linq to sql】专用扩展方法,不建议直接使用
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:FreeSqlExtensionsLinqSql.SelectMany``3(FreeSql.ISelect{``0},System.Linq.Expressions.Expression{System.Func{``0,FreeSql.ISelect{``1}}},System.Linq.Expressions.Expression{System.Func{``0,``1,``2}})">
|
||||
<summary>
|
||||
【linq to sql】专用扩展方法,不建议直接使用
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:FreeSqlExtensionsLinqSql.DefaultIfEmpty``1(FreeSql.ISelect{``0})">
|
||||
<summary>
|
||||
【linq to sql】专用扩展方法,不建议直接使用
|
||||
</summary>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
131
Extensions/FreeSql.Extensions.Linq/FreeSqlExtensionsLinq.cs
Normal file
131
Extensions/FreeSql.Extensions.Linq/FreeSqlExtensionsLinq.cs
Normal file
@ -0,0 +1,131 @@
|
||||
using FreeSql;
|
||||
using FreeSql.Extensions.Linq;
|
||||
using FreeSql.Internal;
|
||||
using FreeSql.Internal.CommonProvider;
|
||||
using FreeSql.Internal.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
public static class FreeSqlExtensionsLinqSql
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 将 ISelect<T1> 转换为 IQueryable<T1><para></para>
|
||||
/// 此方法主要用于扩展,比如:abp IRepository GetAll() 接口方法需要返回 IQueryable 对象<para></para>
|
||||
/// 注意:IQueryable 方法污染较为严重,请尽量避免此转换
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<T1> AsQueryable<T1>(this ISelect<T1> that) where T1 : class
|
||||
{
|
||||
return new QueryableProvider<T1, T1>(that as Select1Provider<T1>);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 【linq to sql】专用扩展方法,不建议直接使用
|
||||
/// </summary>
|
||||
public static ISelect<TReturn> Select<T1, TReturn>(this ISelect<T1> that, Expression<Func<T1, TReturn>> select) where T1 : class where TReturn : class
|
||||
{
|
||||
var s1p = that as Select1Provider<T1>;
|
||||
if (typeof(TReturn) == typeof(T1)) return that as ISelect<TReturn>;
|
||||
s1p._tables[0].Parameter = select.Parameters[0];
|
||||
s1p._selectExpression = select.Body;
|
||||
if (s1p._orm.CodeFirst.IsAutoSyncStructure)
|
||||
(s1p._orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(TReturn)); //._dicSyced.TryAdd(typeof(TReturn), true);
|
||||
var ret = s1p._orm.Select<TReturn>() as Select1Provider<TReturn>;
|
||||
Select0Provider.CopyData(s1p, ret, null);
|
||||
return ret;
|
||||
}
|
||||
/// <summary>
|
||||
/// 【linq to sql】专用扩展方法,不建议直接使用
|
||||
/// </summary>
|
||||
public static ISelect<TResult> Join<T1, TInner, TKey, TResult>(this ISelect<T1> that, ISelect<TInner> inner, Expression<Func<T1, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<T1, TInner, TResult>> resultSelector) where T1 : class where TInner : class where TResult : class
|
||||
{
|
||||
var s1p = that as Select1Provider<T1>;
|
||||
InternalJoin2(s1p, outerKeySelector, innerKeySelector, resultSelector);
|
||||
if (typeof(TResult) == typeof(T1)) return that as ISelect<TResult>;
|
||||
s1p._selectExpression = resultSelector.Body;
|
||||
if (s1p._orm.CodeFirst.IsAutoSyncStructure)
|
||||
(s1p._orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(TResult)); //._dicSyced.TryAdd(typeof(TResult), true);
|
||||
var ret = s1p._orm.Select<TResult>() as Select1Provider<TResult>;
|
||||
Select0Provider.CopyData(s1p, ret, null);
|
||||
return ret;
|
||||
}
|
||||
internal static void InternalJoin2<T1>(Select1Provider<T1> s1p, LambdaExpression outerKeySelector, LambdaExpression innerKeySelector, LambdaExpression resultSelector) where T1 : class
|
||||
{
|
||||
s1p._tables[0].Parameter = resultSelector.Parameters[0];
|
||||
s1p._commonExpression.ExpressionLambdaToSql(outerKeySelector, new CommonExpression.ExpTSC { _tables = s1p._tables });
|
||||
s1p.InternalJoin(Expression.Lambda(typeof(Func<,,>).MakeGenericType(typeof(T1), innerKeySelector.Parameters[0].Type, typeof(bool)),
|
||||
Expression.Equal(outerKeySelector.Body, innerKeySelector.Body),
|
||||
new[] { outerKeySelector.Parameters[0], innerKeySelector.Parameters[0] }
|
||||
), SelectTableInfoType.InnerJoin);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 【linq to sql】专用扩展方法,不建议直接使用
|
||||
/// </summary>
|
||||
public static ISelect<TResult> GroupJoin<T1, TInner, TKey, TResult>(this ISelect<T1> that, ISelect<TInner> inner, Expression<Func<T1, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<T1, ISelect<TInner>, TResult>> resultSelector) where T1 : class where TInner : class where TResult : class
|
||||
{
|
||||
var s1p = that as Select1Provider<T1>;
|
||||
InternalJoin2(s1p, outerKeySelector, innerKeySelector, resultSelector);
|
||||
if (typeof(TResult) == typeof(T1)) return that as ISelect<TResult>;
|
||||
s1p._selectExpression = resultSelector.Body;
|
||||
if (s1p._orm.CodeFirst.IsAutoSyncStructure)
|
||||
(s1p._orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(TResult)); //._dicSyced.TryAdd(typeof(TResult), true);
|
||||
var ret = s1p._orm.Select<TResult>() as Select1Provider<TResult>;
|
||||
Select0Provider.CopyData(s1p, ret, null);
|
||||
return ret;
|
||||
}
|
||||
/// <summary>
|
||||
/// 【linq to sql】专用扩展方法,不建议直接使用
|
||||
/// </summary>
|
||||
public static ISelect<TResult> SelectMany<T1, TCollection, TResult>(this ISelect<T1> that, Expression<Func<T1, ISelect<TCollection>>> collectionSelector, Expression<Func<T1, TCollection, TResult>> resultSelector) where T1 : class where TCollection : class where TResult : class
|
||||
{
|
||||
var s1p = that as Select1Provider<T1>;
|
||||
InternalSelectMany2(s1p, collectionSelector, resultSelector);
|
||||
if (typeof(TResult) == typeof(T1)) return that as ISelect<TResult>;
|
||||
s1p._selectExpression = resultSelector.Body;
|
||||
if (s1p._orm.CodeFirst.IsAutoSyncStructure)
|
||||
(s1p._orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(TResult)); //._dicSyced.TryAdd(typeof(TResult), true);
|
||||
var ret = s1p._orm.Select<TResult>() as Select1Provider<TResult>;
|
||||
Select0Provider.CopyData(s1p, ret, null);
|
||||
return ret;
|
||||
}
|
||||
internal static void InternalSelectMany2<T1>(Select1Provider<T1> s1p, LambdaExpression collectionSelector, LambdaExpression resultSelector) where T1 : class
|
||||
{
|
||||
SelectTableInfo find = null;
|
||||
if (collectionSelector.Body.NodeType == ExpressionType.Call)
|
||||
{
|
||||
var callExp = collectionSelector.Body as MethodCallExpression;
|
||||
if (callExp.Method.Name == "DefaultIfEmpty" && callExp.Method.GetGenericArguments().Any())
|
||||
{
|
||||
find = s1p._tables.Where((a, idx) => idx > 0 && a.Type == SelectTableInfoType.InnerJoin && a.Table.Type == callExp.Method.GetGenericArguments()[0]).LastOrDefault();
|
||||
if (find != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(find.On)) find.On = Regex.Replace(find.On, $@"\b{find.Alias}\.", $"{resultSelector.Parameters[1].Name}.");
|
||||
if (!string.IsNullOrEmpty(find.NavigateCondition)) find.NavigateCondition = Regex.Replace(find.NavigateCondition, $@"\b{find.Alias}\.", $"{resultSelector.Parameters[1].Name}.");
|
||||
find.Type = SelectTableInfoType.LeftJoin;
|
||||
find.Alias = resultSelector.Parameters[1].Name;
|
||||
find.Parameter = resultSelector.Parameters[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (find == null)
|
||||
{
|
||||
var tb = s1p._commonUtils.GetTableByEntity(resultSelector.Parameters[1].Type);
|
||||
if (tb == null) throw new Exception($"SelectMany 错误的类型:{resultSelector.Parameters[1].Type.FullName}");
|
||||
s1p._tables.Add(new SelectTableInfo { Alias = resultSelector.Parameters[1].Name, AliasInit = resultSelector.Parameters[1].Name, Parameter = resultSelector.Parameters[1], Table = tb, Type = SelectTableInfoType.From });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 【linq to sql】专用扩展方法,不建议直接使用
|
||||
/// </summary>
|
||||
public static ISelect<T1> DefaultIfEmpty<T1>(this ISelect<T1> that) where T1 : class
|
||||
{
|
||||
return that;
|
||||
}
|
||||
}
|
279
Extensions/FreeSql.Extensions.Linq/QueryableProvider.cs
Normal file
279
Extensions/FreeSql.Extensions.Linq/QueryableProvider.cs
Normal file
@ -0,0 +1,279 @@
|
||||
using FreeSql.Internal;
|
||||
using FreeSql.Internal.CommonProvider;
|
||||
using FreeSql.Internal.Model;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace FreeSql.Extensions.Linq
|
||||
{
|
||||
class QueryableProvider<TCurrent, TSource> : IQueryable<TCurrent>, IOrderedQueryable<TCurrent> where TSource : class
|
||||
{
|
||||
private Expression _expression;
|
||||
private IQueryProvider _provider;
|
||||
private Select1Provider<TSource> _select;
|
||||
|
||||
public QueryableProvider(Select1Provider<TSource> select)
|
||||
{
|
||||
_select = select;
|
||||
_expression = Expression.Constant(this);
|
||||
_provider = new QueryProvider<TCurrent, TSource>(_select);
|
||||
}
|
||||
public QueryableProvider(Expression expression, IQueryProvider provider, Select1Provider<TSource> select)
|
||||
{
|
||||
_select = select;
|
||||
_expression = expression;
|
||||
_provider = provider;
|
||||
}
|
||||
|
||||
public IEnumerator<TCurrent> GetEnumerator()
|
||||
{
|
||||
var result = _provider.Execute<List<TCurrent>>(_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<TCurrent, TSource>);
|
||||
public Expression Expression => _expression;
|
||||
public IQueryProvider Provider => _provider;
|
||||
}
|
||||
|
||||
class QueryProvider<TCurrent, TSource> : IQueryProvider where TSource : class
|
||||
{
|
||||
private Select1Provider<TSource> _select;
|
||||
|
||||
public QueryProvider(Select1Provider<TSource> select)
|
||||
{
|
||||
_select = select;
|
||||
}
|
||||
|
||||
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
|
||||
{
|
||||
if (typeof(TElement) != typeof(TCurrent))
|
||||
return new QueryableProvider<TElement, TSource>(expression, new QueryProvider<TElement, TSource>(_select), _select);
|
||||
|
||||
return new QueryableProvider<TElement, TSource>(expression, this, _select);
|
||||
}
|
||||
public IQueryable CreateQuery(Expression expression) => throw new NotImplementedException();
|
||||
|
||||
public TResult Execute<TResult>(Expression expression)
|
||||
{
|
||||
var stackCallExps = new Stack<MethodCallExpression>();
|
||||
var callExp = expression as MethodCallExpression;
|
||||
while(callExp != null)
|
||||
{
|
||||
stackCallExps.Push(callExp);
|
||||
callExp = callExp?.Arguments.FirstOrDefault() as MethodCallExpression;
|
||||
}
|
||||
|
||||
SelectGroupingProvider groupBy = null;
|
||||
var isfirst = false;
|
||||
while (stackCallExps.Any())
|
||||
{
|
||||
callExp = stackCallExps.Pop();
|
||||
TResult throwCallExp(string message) => throw new Exception($"FreeSql Queryable 解析出错,执行的方法 {callExp.Method.Name} {message}");
|
||||
if (callExp.Method.DeclaringType != typeof(Queryable)) return throwCallExp($"必须属于 System.Linq.Enumerable");
|
||||
|
||||
TResult tplMaxMinAvgSum(string method) {
|
||||
if (callExp.Arguments.Count == 2)
|
||||
{
|
||||
var avgParam = (callExp.Arguments[1] as UnaryExpression)?.Operand as LambdaExpression;
|
||||
return (TResult)Utils.GetDataReaderValue(typeof(TResult),
|
||||
_select.GetType().GetMethod(method).MakeGenericMethod(avgParam.ReturnType).Invoke(_select, new object[] { avgParam }));
|
||||
}
|
||||
return throwCallExp($" 不支持 {callExp.Arguments.Count}个参数的方法");
|
||||
}
|
||||
TResult tplOrderBy(string method, bool isDescending)
|
||||
{
|
||||
if (callExp.Arguments.Count == 2)
|
||||
{
|
||||
var arg1 = (callExp.Arguments[1] as UnaryExpression)?.Operand as LambdaExpression;
|
||||
_select.OrderByReflection(arg1, isDescending);
|
||||
return default(TResult);
|
||||
}
|
||||
return throwCallExp($" 不支持 {callExp.Arguments.Count}个参数的方法");
|
||||
}
|
||||
switch (callExp.Method.Name)
|
||||
{
|
||||
case "Any":
|
||||
if (callExp.Arguments.Count == 2) _select.Where((Expression<Func<TSource, bool>>)(callExp.Arguments[1] as UnaryExpression)?.Operand);
|
||||
return (TResult)(object)_select.Any();
|
||||
case "AsQueryable":
|
||||
break;
|
||||
|
||||
case "Max": return tplMaxMinAvgSum("Max");
|
||||
case "Min": return tplMaxMinAvgSum("Min");
|
||||
case "Sum": return tplMaxMinAvgSum("Sum");
|
||||
case "Average": return tplMaxMinAvgSum("Avg");
|
||||
|
||||
case "Concat":
|
||||
return throwCallExp(" 不支持");
|
||||
case "Contains":
|
||||
if (callExp.Arguments.Count == 2)
|
||||
{
|
||||
var dywhere = (callExp.Arguments[1] as ConstantExpression)?.Value as TSource;
|
||||
if (dywhere == null) return throwCallExp($" 参数值不能为 null");
|
||||
_select.WhereDynamic(dywhere);
|
||||
return (TResult)(object)_select.Any();
|
||||
}
|
||||
return throwCallExp($" 不支持 {callExp.Arguments.Count}个参数的方法");
|
||||
case "Count":
|
||||
if (callExp.Arguments.Count == 2) _select.Where((Expression<Func<TSource, bool>>)(callExp.Arguments[1] as UnaryExpression)?.Operand);
|
||||
return (TResult)Utils.GetDataReaderValue(typeof(TResult), _select.Count());
|
||||
|
||||
case "Distinct":
|
||||
if (callExp.Arguments.Count == 1)
|
||||
{
|
||||
_select.Distinct();
|
||||
break;
|
||||
}
|
||||
return throwCallExp(" 不支持");
|
||||
|
||||
case "ElementAt":
|
||||
case "ElementAtOrDefault":
|
||||
_select.Offset((int)(callExp.Arguments[1] as ConstantExpression)?.Value);
|
||||
_select.Limit(1);
|
||||
isfirst = true;
|
||||
break;
|
||||
case "First":
|
||||
case "FirstOrDefault":
|
||||
case "Single":
|
||||
case "SingleOrDefault":
|
||||
if (callExp.Arguments.Count == 2) _select.Where((Expression<Func<TSource, bool>>)(callExp.Arguments[1] as UnaryExpression)?.Operand);
|
||||
_select.Limit(1);
|
||||
isfirst = true;
|
||||
break;
|
||||
|
||||
case "OrderBy":
|
||||
tplOrderBy("OrderByReflection", false);
|
||||
break;
|
||||
case "OrderByDescending":
|
||||
tplOrderBy("OrderByReflection", true);
|
||||
break;
|
||||
case "ThenBy":
|
||||
tplOrderBy("OrderByReflection", false);
|
||||
break;
|
||||
case "ThenByDescending":
|
||||
tplOrderBy("OrderByReflection", true);
|
||||
break;
|
||||
|
||||
case "Where":
|
||||
var whereParam = (callExp.Arguments[1] as UnaryExpression)?.Operand as LambdaExpression;
|
||||
if (whereParam.Parameters.Count == 1)
|
||||
{
|
||||
if (groupBy != null) groupBy.InternalHaving(whereParam);
|
||||
else _select.InternalWhere(whereParam);
|
||||
break;
|
||||
}
|
||||
return throwCallExp(" 不支持");
|
||||
|
||||
case "Skip":
|
||||
_select.Offset((int)(callExp.Arguments[1] as ConstantExpression)?.Value);
|
||||
break;
|
||||
case "Take":
|
||||
_select.Limit((int)(callExp.Arguments[1] as ConstantExpression)?.Value);
|
||||
break;
|
||||
|
||||
case "ToList":
|
||||
if (callExp.Arguments.Count == 1)
|
||||
return (TResult)(object)_select.ToList();
|
||||
return throwCallExp(" 不支持");
|
||||
|
||||
|
||||
case "Select":
|
||||
var selectParam = (callExp.Arguments[1] as UnaryExpression)?.Operand as LambdaExpression;
|
||||
if (selectParam.Parameters.Count == 1)
|
||||
{
|
||||
_select._selectExpression = selectParam;
|
||||
break;
|
||||
}
|
||||
return throwCallExp(" 不支持");
|
||||
|
||||
case "Join":
|
||||
if (callExp.Arguments.Count == 5)
|
||||
{
|
||||
var arg2 = (callExp.Arguments[2] as UnaryExpression)?.Operand as LambdaExpression;
|
||||
var arg3 = (callExp.Arguments[3] as UnaryExpression)?.Operand as LambdaExpression;
|
||||
var arg4 = (callExp.Arguments[4] as UnaryExpression)?.Operand as LambdaExpression;
|
||||
FreeSqlExtensionsLinqSql.InternalJoin2(_select, arg2, arg3, arg4);
|
||||
_select._selectExpression = arg4.Body;
|
||||
break;
|
||||
}
|
||||
return throwCallExp($" 不支持 {callExp.Arguments.Count}个参数的方法");
|
||||
|
||||
case "GroupJoin":
|
||||
if (callExp.Arguments.Count == 5)
|
||||
{
|
||||
var arg2 = (callExp.Arguments[2] as UnaryExpression)?.Operand as LambdaExpression;
|
||||
var arg3 = (callExp.Arguments[3] as UnaryExpression)?.Operand as LambdaExpression;
|
||||
var arg4 = (callExp.Arguments[4] as UnaryExpression)?.Operand as LambdaExpression;
|
||||
FreeSqlExtensionsLinqSql.InternalJoin2(_select, arg2, arg3, arg4);
|
||||
_select._selectExpression = arg4.Body;
|
||||
break;
|
||||
}
|
||||
return throwCallExp($" 不支持 {callExp.Arguments.Count}个参数的方法");
|
||||
|
||||
case "SelectMany":
|
||||
if (callExp.Arguments.Count == 3)
|
||||
{
|
||||
var arg1 = (callExp.Arguments[1] as UnaryExpression)?.Operand as LambdaExpression;
|
||||
var arg2 = (callExp.Arguments[2] as UnaryExpression)?.Operand as LambdaExpression;
|
||||
FreeSqlExtensionsLinqSql.InternalSelectMany2(_select, arg1, arg2);
|
||||
_select._selectExpression = arg2.Body;
|
||||
break;
|
||||
}
|
||||
return throwCallExp($" 不支持 {callExp.Arguments.Count}个参数的方法");
|
||||
|
||||
case "DefaultIfEmpty":
|
||||
break;
|
||||
|
||||
case "Last":
|
||||
case "LastOrDefault":
|
||||
return throwCallExp(" 不支持");
|
||||
|
||||
case "GroupBy":
|
||||
return throwCallExp(" 不支持");
|
||||
|
||||
if (callExp.Arguments.Count == 2) //TODO: 待实现
|
||||
{
|
||||
var arg1 = (callExp.Arguments[1] as UnaryExpression)?.Operand as LambdaExpression;
|
||||
|
||||
var map = new ReadAnonymousTypeInfo();
|
||||
var field = new StringBuilder();
|
||||
var index = -10000; //临时规则,不返回 as1
|
||||
|
||||
_select._commonExpression.ReadAnonymousField(_select._tables, field, map, ref index, arg1, null, _select._whereCascadeExpression, false); //不走 DTO 映射
|
||||
var sql = field.ToString();
|
||||
_select.GroupBy(sql.Length > 0 ? sql.Substring(2) : null);
|
||||
groupBy = new SelectGroupingProvider(_select._orm, _select, map, sql, _select._commonExpression, _select._tables);
|
||||
break;
|
||||
}
|
||||
return throwCallExp($" 不支持 {callExp.Arguments.Count}个参数的方法");
|
||||
|
||||
default:
|
||||
return throwCallExp(" 不支持");
|
||||
}
|
||||
}
|
||||
if (isfirst)
|
||||
{
|
||||
_select.Limit(1);
|
||||
if (_select._selectExpression != null)
|
||||
return (TResult)(object)_select.InternalToList<TCurrent>(_select._selectExpression).FirstOrDefault();
|
||||
return (TResult)(object)_select.ToList().FirstOrDefault();
|
||||
}
|
||||
if (_select._selectExpression != null)
|
||||
return (TResult)(object)_select.InternalToList<TCurrent>(_select._selectExpression);
|
||||
return (TResult)(object)_select.ToList();
|
||||
}
|
||||
public object Execute(Expression expression) => throw new NotImplementedException();
|
||||
}
|
||||
}
|
BIN
Extensions/FreeSql.Extensions.Linq/key.snk
Normal file
BIN
Extensions/FreeSql.Extensions.Linq/key.snk
Normal file
Binary file not shown.
Reference in New Issue
Block a user