From 5f987496526d178cca89f5a72ff27e8b5cdcc259 Mon Sep 17 00:00:00 2001
From: 28810 <28810@YEXIANGQIN>
Date: Fri, 10 Apr 2020 02:28:33 +0800
Subject: [PATCH] =?UTF-8?q?-=20=E8=B0=83=E6=95=B4=20ISelect=20linq=20to=20?=
=?UTF-8?q?sql=20=E5=92=8C=20queryable=20=E5=AE=9E=E7=8E=B0=E4=BE=9D?=
=?UTF-8?q?=E8=B5=96=E7=A7=BB=E8=87=B3=20FreeSql.Extensions.Linq=EF=BC=9B#?=
=?UTF-8?q?260?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../FreeSql.Extensions.Linq.csproj | 37 +++
.../FreeSql.Extensions.Linq.xml | 41 +++
.../FreeSqlExtensionsLinq.cs | 131 ++++++++
.../QueryableProvider.cs | 279 ++++++++++++++++++
Extensions/FreeSql.Extensions.Linq/key.snk | Bin 0 -> 596 bytes
.../Repository/Repository/BaseRepository.cs | 8 +-
.../Repository/BaseRepositoryAsync.cs | 8 +-
.../FreeSql.Tests.Provider.Odbc/UnitTest1.cs | 11 -
.../FreeSql.Tests/FreeSql.Tests.csproj | 1 +
.../Queryable/QueryableLinqToSqlTests.cs | 202 +++++++++++++
.../FreeSql.Tests/Queryable/QueryableTest.cs | 122 +++++++-
FreeSql.sln | 15 +
FreeSql/FreeSql.xml | 33 ---
FreeSql/Interface/Curd/ISelect/ILinqToSql.cs | 31 --
FreeSql/Interface/Curd/ISelect/ISelect1.cs | 10 +-
FreeSql/Internal/CommonExpression.cs | 43 +--
.../CommonProvider/CodeFirstProvider.cs | 3 +-
.../SelectProvider/QueryableProvider.cs | 107 -------
.../SelectProvider/Select0Provider.cs | 113 +++----
.../SelectProvider/Select1Provider.cs | 122 ++------
.../SelectProvider/SelectGroupingProvider.cs | 105 +++----
21 files changed, 987 insertions(+), 435 deletions(-)
create mode 100644 Extensions/FreeSql.Extensions.Linq/FreeSql.Extensions.Linq.csproj
create mode 100644 Extensions/FreeSql.Extensions.Linq/FreeSql.Extensions.Linq.xml
create mode 100644 Extensions/FreeSql.Extensions.Linq/FreeSqlExtensionsLinq.cs
create mode 100644 Extensions/FreeSql.Extensions.Linq/QueryableProvider.cs
create mode 100644 Extensions/FreeSql.Extensions.Linq/key.snk
create mode 100644 FreeSql.Tests/FreeSql.Tests/Queryable/QueryableLinqToSqlTests.cs
delete mode 100644 FreeSql/Interface/Curd/ISelect/ILinqToSql.cs
delete mode 100644 FreeSql/Internal/CommonProvider/SelectProvider/QueryableProvider.cs
diff --git a/Extensions/FreeSql.Extensions.Linq/FreeSql.Extensions.Linq.csproj b/Extensions/FreeSql.Extensions.Linq/FreeSql.Extensions.Linq.csproj
new file mode 100644
index 00000000..202f9ed5
--- /dev/null
+++ b/Extensions/FreeSql.Extensions.Linq/FreeSql.Extensions.Linq.csproj
@@ -0,0 +1,37 @@
+
+
+
+ netstandard2.0;net45;net40
+ 1.4.0-preview20200410
+ true
+ YeXiangQin
+ FreeSql 扩展包,实现 linq queryable 和 linq to sql 语法进行开发.
+ https://github.com/2881099/FreeSql
+ https://github.com/2881099/FreeSql
+ git
+ MIT
+ FreeSql;ORM
+ $(AssemblyName)
+ logo.png
+ $(AssemblyName)
+ true
+ true
+ true
+ key.snk
+ false
+
+
+
+
+
+
+
+ FreeSql.Extensions.Linq.xml
+ 3
+
+
+
+
+
+
+
diff --git a/Extensions/FreeSql.Extensions.Linq/FreeSql.Extensions.Linq.xml b/Extensions/FreeSql.Extensions.Linq/FreeSql.Extensions.Linq.xml
new file mode 100644
index 00000000..19871dd2
--- /dev/null
+++ b/Extensions/FreeSql.Extensions.Linq/FreeSql.Extensions.Linq.xml
@@ -0,0 +1,41 @@
+
+
+
+ FreeSql.Extensions.Linq
+
+
+
+
+ 将 ISelect<T1> 转换为 IQueryable<T1>
+ 此方法主要用于扩展,比如:abp IRepository GetAll() 接口方法需要返回 IQueryable 对象
+ 注意:IQueryable 方法污染较为严重,请尽量避免此转换
+
+
+
+
+
+ 【linq to sql】专用扩展方法,不建议直接使用
+
+
+
+
+ 【linq to sql】专用扩展方法,不建议直接使用
+
+
+
+
+ 【linq to sql】专用扩展方法,不建议直接使用
+
+
+
+
+ 【linq to sql】专用扩展方法,不建议直接使用
+
+
+
+
+ 【linq to sql】专用扩展方法,不建议直接使用
+
+
+
+
diff --git a/Extensions/FreeSql.Extensions.Linq/FreeSqlExtensionsLinq.cs b/Extensions/FreeSql.Extensions.Linq/FreeSqlExtensionsLinq.cs
new file mode 100644
index 00000000..de256cec
--- /dev/null
+++ b/Extensions/FreeSql.Extensions.Linq/FreeSqlExtensionsLinq.cs
@@ -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
+{
+
+ ///
+ /// 将 ISelect<T1> 转换为 IQueryable<T1>
+ /// 此方法主要用于扩展,比如:abp IRepository GetAll() 接口方法需要返回 IQueryable 对象
+ /// 注意:IQueryable 方法污染较为严重,请尽量避免此转换
+ ///
+ ///
+ public static IQueryable AsQueryable(this ISelect that) where T1 : class
+ {
+ return new QueryableProvider(that as Select1Provider);
+ }
+
+ ///
+ /// 【linq to sql】专用扩展方法,不建议直接使用
+ ///
+ public static ISelect Select(this ISelect that, Expression> select) where T1 : class where TReturn : class
+ {
+ var s1p = that as Select1Provider;
+ if (typeof(TReturn) == typeof(T1)) return that as ISelect;
+ 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() as Select1Provider;
+ Select0Provider.CopyData(s1p, ret, null);
+ return ret;
+ }
+ ///
+ /// 【linq to sql】专用扩展方法,不建议直接使用
+ ///
+ public static ISelect Join(this ISelect that, ISelect inner, Expression> outerKeySelector, Expression> innerKeySelector, Expression> resultSelector) where T1 : class where TInner : class where TResult : class
+ {
+ var s1p = that as Select1Provider;
+ InternalJoin2(s1p, outerKeySelector, innerKeySelector, resultSelector);
+ if (typeof(TResult) == typeof(T1)) return that as ISelect;
+ 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() as Select1Provider;
+ Select0Provider.CopyData(s1p, ret, null);
+ return ret;
+ }
+ internal static void InternalJoin2(Select1Provider 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);
+ }
+
+ ///
+ /// 【linq to sql】专用扩展方法,不建议直接使用
+ ///
+ public static ISelect GroupJoin(this ISelect that, ISelect inner, Expression> outerKeySelector, Expression> innerKeySelector, Expression, TResult>> resultSelector) where T1 : class where TInner : class where TResult : class
+ {
+ var s1p = that as Select1Provider;
+ InternalJoin2(s1p, outerKeySelector, innerKeySelector, resultSelector);
+ if (typeof(TResult) == typeof(T1)) return that as ISelect;
+ 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() as Select1Provider;
+ Select0Provider.CopyData(s1p, ret, null);
+ return ret;
+ }
+ ///
+ /// 【linq to sql】专用扩展方法,不建议直接使用
+ ///
+ public static ISelect SelectMany(this ISelect that, Expression>> collectionSelector, Expression> resultSelector) where T1 : class where TCollection : class where TResult : class
+ {
+ var s1p = that as Select1Provider;
+ InternalSelectMany2(s1p, collectionSelector, resultSelector);
+ if (typeof(TResult) == typeof(T1)) return that as ISelect;
+ 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() as Select1Provider;
+ Select0Provider.CopyData(s1p, ret, null);
+ return ret;
+ }
+ internal static void InternalSelectMany2(Select1Provider 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 });
+ }
+ }
+
+ ///
+ /// 【linq to sql】专用扩展方法,不建议直接使用
+ ///
+ public static ISelect DefaultIfEmpty(this ISelect that) where T1 : class
+ {
+ return that;
+ }
+}
diff --git a/Extensions/FreeSql.Extensions.Linq/QueryableProvider.cs b/Extensions/FreeSql.Extensions.Linq/QueryableProvider.cs
new file mode 100644
index 00000000..892e1cf8
--- /dev/null
+++ b/Extensions/FreeSql.Extensions.Linq/QueryableProvider.cs
@@ -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 : IQueryable, IOrderedQueryable where TSource : class
+ {
+ private Expression _expression;
+ private IQueryProvider _provider;
+ private Select1Provider _select;
+
+ public QueryableProvider(Select1Provider select)
+ {
+ _select = select;
+ _expression = Expression.Constant(this);
+ _provider = new QueryProvider(_select);
+ }
+ public QueryableProvider(Expression expression, IQueryProvider provider, Select1Provider select)
+ {
+ _select = select;
+ _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 where TSource : class
+ {
+ private Select1Provider _select;
+
+ public QueryProvider(Select1Provider select)
+ {
+ _select = select;
+ }
+
+ public IQueryable CreateQuery(Expression expression)
+ {
+ if (typeof(TElement) != typeof(TCurrent))
+ return new QueryableProvider(expression, new QueryProvider(_select), _select);
+
+ return new QueryableProvider(expression, this, _select);
+ }
+ public IQueryable CreateQuery(Expression expression) => throw new NotImplementedException();
+
+ public TResult Execute(Expression expression)
+ {
+ var stackCallExps = new Stack();
+ 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>)(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>)(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>)(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(_select._selectExpression).FirstOrDefault();
+ return (TResult)(object)_select.ToList().FirstOrDefault();
+ }
+ if (_select._selectExpression != null)
+ return (TResult)(object)_select.InternalToList(_select._selectExpression);
+ return (TResult)(object)_select.ToList();
+ }
+ public object Execute(Expression expression) => throw new NotImplementedException();
+ }
+}
diff --git a/Extensions/FreeSql.Extensions.Linq/key.snk b/Extensions/FreeSql.Extensions.Linq/key.snk
new file mode 100644
index 0000000000000000000000000000000000000000..e580bc8d5d64e7c5a0c62b971545d38cfbe7d837
GIT binary patch
literal 596
zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50096c(W3|+clf|4d2=6Xc+R`Gd@9@k@Meh}
zR8`}1=JPk=q?Zlr?i$1O?SgX-{{&z
z|LRF?-aWODhAO}h_7M!wz}uPXx}n-g{((r9{{%_
z4)%gVXcj;Ru@GYAIZI@e#GBtO#O5m-Qr4X_lbAV}=qNRkd0^`@I6i9k`wSe@ZPxVo
zk;MXig(S-cYHE!0GWWlp7EH@E!WkF6jS+3z4rvW0%Sq;U1bq`B9*HNJjxo*23*7Vw
zHyt>{2CR~8==`lYLgAmwsXPXYZ_AEAKy|PuUz0(G)L1xO{{*n6Bn?mV~QKg!055THihpc>GOh(U-NgO?4_DzY4uq!p9=Q;`G
i9;v3GkC674Mbx4_b$)?7a0%Z%&zUjzbGs@!l^s|B
literal 0
HcmV?d00001
diff --git a/FreeSql.DbContext/Repository/Repository/BaseRepository.cs b/FreeSql.DbContext/Repository/Repository/BaseRepository.cs
index cc8ec1bf..0670666f 100644
--- a/FreeSql.DbContext/Repository/Repository/BaseRepository.cs
+++ b/FreeSql.DbContext/Repository/Repository/BaseRepository.cs
@@ -73,7 +73,7 @@ namespace FreeSql
public ISelect Where(Expression> exp) => _dbset.OrmSelectInternal(null).Where(exp);
public ISelect WhereIf(bool condition, Expression> exp) => _dbset.OrmSelectInternal(null).WhereIf(condition, exp);
- public int Delete(Expression> predicate)
+ public virtual int Delete(Expression> predicate)
{
var delete = _dbset.OrmDeleteInternal(null).Where(predicate);
var sql = delete.ToSql();
@@ -82,12 +82,12 @@ namespace FreeSql
return affrows;
}
- public int Delete(TEntity entity)
+ public virtual int Delete(TEntity entity)
{
_dbset.Remove(entity);
return _db.SaveChanges();
}
- public int Delete(IEnumerable entitys)
+ public virtual int Delete(IEnumerable entitys)
{
_dbset.RemoveRange(entitys);
return _db.SaveChanges();
@@ -157,7 +157,7 @@ namespace FreeSql
return ret;
}
- public int Delete(TKey id) => Delete(CheckTKeyAndReturnIdEntity(id));
+ public virtual int Delete(TKey id) => Delete(CheckTKeyAndReturnIdEntity(id));
public TEntity Find(TKey id) => _dbset.OrmSelectInternal(CheckTKeyAndReturnIdEntity(id)).ToOne();
public TEntity Get(TKey id) => Find(id);
}
diff --git a/FreeSql.DbContext/Repository/Repository/BaseRepositoryAsync.cs b/FreeSql.DbContext/Repository/Repository/BaseRepositoryAsync.cs
index c3e5dd42..3cded670 100644
--- a/FreeSql.DbContext/Repository/Repository/BaseRepositoryAsync.cs
+++ b/FreeSql.DbContext/Repository/Repository/BaseRepositoryAsync.cs
@@ -13,7 +13,7 @@ namespace FreeSql
where TEntity : class
{
- async public Task DeleteAsync(Expression> predicate)
+ async virtual public Task DeleteAsync(Expression> predicate)
{
var delete = _dbset.OrmDeleteInternal(null).Where(predicate);
var sql = delete.ToSql();
@@ -22,12 +22,12 @@ namespace FreeSql
return affrows;
}
- public Task DeleteAsync(TEntity entity)
+ public virtual Task DeleteAsync(TEntity entity)
{
_dbset.Remove(entity);
return _db.SaveChangesAsync();
}
- public Task DeleteAsync(IEnumerable entitys)
+ public virtual Task DeleteAsync(IEnumerable entitys)
{
_dbset.RemoveRange(entitys);
return _db.SaveChangesAsync();
@@ -73,7 +73,7 @@ namespace FreeSql
partial class BaseRepository
{
- public Task DeleteAsync(TKey id) => DeleteAsync(CheckTKeyAndReturnIdEntity(id));
+ public virtual Task DeleteAsync(TKey id) => DeleteAsync(CheckTKeyAndReturnIdEntity(id));
public Task FindAsync(TKey id) => _dbset.OrmSelectInternal(CheckTKeyAndReturnIdEntity(id)).ToOneAsync();
public Task GetAsync(TKey id) => FindAsync(id);
}
diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/UnitTest1.cs b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/UnitTest1.cs
index 5f040d3c..4f26b4ac 100644
--- a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/UnitTest1.cs
+++ b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/UnitTest1.cs
@@ -563,8 +563,6 @@ WHERE ROWNUM < 11";
.UpdateColumns(x => new { x.Status, x.CategoryId, x.ArticleTitle })
.ToSql();
- var sqldddklist = g.mysql.Select().Select(a => new NewsArticleDto { }).ToList();
-
var sql1111333 = g.mysql.Update()
.SetSource(new Model2 { id = 1, Title = "xxx", Parent_id = 0 })
@@ -608,15 +606,6 @@ WHERE ROWNUM < 11";
.ToList();
var ttt1 = g.mysql.Select().Where(a => a.Childs.AsSelect().Any(b => b.Title == "111")).ToList();
-
- var linqto1 =
- from p in g.mysql.Select()
- where p.Id >= 0
- // && p.OrderDetails.AsSelect().Where(c => c.Id > 10).Any()
- orderby p.Id descending
- orderby p.CustomerName ascending
- select new { Name = p.CustomerName, Length = p.Id };
-
var testpid1 = g.mysql.Insert().AppendData(new TestTypeInfo { Name = "Name" + DateTime.Now.ToString("yyyyMMddHHmmss") }).ExecuteIdentity();
g.mysql.Insert().AppendData(new TestInfo { Title = "Title" + DateTime.Now.ToString("yyyyMMddHHmmss"), CreateTime = DateTime.Now, TypeGuid = (int)testpid1 }).ExecuteAffrows();
diff --git a/FreeSql.Tests/FreeSql.Tests/FreeSql.Tests.csproj b/FreeSql.Tests/FreeSql.Tests/FreeSql.Tests.csproj
index e2398841..7fd0f8e7 100644
--- a/FreeSql.Tests/FreeSql.Tests/FreeSql.Tests.csproj
+++ b/FreeSql.Tests/FreeSql.Tests/FreeSql.Tests.csproj
@@ -30,6 +30,7 @@
+
diff --git a/FreeSql.Tests/FreeSql.Tests/Queryable/QueryableLinqToSqlTests.cs b/FreeSql.Tests/FreeSql.Tests/Queryable/QueryableLinqToSqlTests.cs
new file mode 100644
index 00000000..f028f93a
--- /dev/null
+++ b/FreeSql.Tests/FreeSql.Tests/Queryable/QueryableLinqToSqlTests.cs
@@ -0,0 +1,202 @@
+using FreeSql.DataAnnotations;
+using System;
+using System.Linq;
+using Xunit;
+
+namespace FreeSql.Tests.Linq
+{
+
+
+ class TestQueryableLinqToSql
+ {
+ public Guid id { get; set; }
+
+ public string name { get; set; }
+
+ public int click { get; set; } = 10;
+
+ public DateTime createtime { get; set; } = DateTime.Now;
+ }
+ class TestQueryableLinqToSqlComment
+ {
+ public Guid id { get; set; }
+
+ public Guid TestLinqToSqlId { get; set; }
+ public TestQueryableLinqToSql TEstLinqToSql { get; set; }
+
+ public string text { get; set; }
+
+ public DateTime createtime { get; set; } = DateTime.Now;
+ }
+
+ public class QueryableLinqToSqlTests
+ {
+
+ [Fact]
+ public void Where()
+ {
+ var item = new TestQueryableLinqToSql { name = Guid.NewGuid().ToString() };
+ g.sqlite.Insert().AppendData(item).ExecuteAffrows();
+
+ var t1 = (from a in g.sqlite.Select().AsQueryable()
+ where a.id == item.id
+ select a).ToList();
+ Assert.True(t1.Any());
+ Assert.Equal(item.id, t1[0].id);
+ }
+
+ [Fact]
+ public void Select()
+ {
+ var item = new TestQueryableLinqToSql { name = Guid.NewGuid().ToString() };
+ g.sqlite.Insert().AppendData(item).ExecuteAffrows();
+
+ var t1 = (from a in g.sqlite.Select().AsQueryable()
+ where a.id == item.id
+ select new { a.id }).ToList();
+ Assert.True(t1.Any());
+ Assert.Equal(item.id, t1[0].id);
+ }
+
+ [Fact]
+ public void GroupBy()
+ {
+ //var item = new TestQueryableLinqToSql { name = Guid.NewGuid().ToString() };
+ //g.sqlite.Insert().AppendData(item).ExecuteAffrows();
+
+ //var t1 = (from a in g.sqlite.Select().AsQueryable()
+ // where a.id == item.id
+ // group a by new { a.id, a.name } into g
+ // select new
+ // {
+ // g.Key.id,
+ // g.Key.name,
+ // cou = g.Count(),
+ // avg = g.Average(x => x.click),
+ // sum = g.Sum(x => x.click),
+ // max = g.Max(x => x.click),
+ // min = g.Min(x => x.click)
+ // }).ToList();
+ //Assert.True(t1.Any());
+ //Assert.Equal(item.id, t1.First().id);
+ }
+
+ [Fact]
+ public void CaseWhen()
+ {
+ var item = new TestQueryableLinqToSql { name = Guid.NewGuid().ToString() };
+ g.sqlite.Insert().AppendData(item).ExecuteAffrows();
+
+ var t1 = (from a in g.sqlite.Select().AsQueryable()
+ where a.id == item.id
+ select new
+ {
+ a.id,
+ a.name,
+ testsub = new
+ {
+ time = a.click > 10 ? "" : "Сڻ"
+ }
+ }).ToList();
+ Assert.True(t1.Any());
+ Assert.Equal(item.id, t1[0].id);
+ Assert.Equal("Сڻ", t1[0].testsub.time);
+ }
+
+ [Fact]
+ public void Join()
+ {
+ var item = new TestQueryableLinqToSql { name = Guid.NewGuid().ToString() };
+ g.sqlite.Insert().AppendData(item).ExecuteAffrows();
+ var comment = new TestQueryableLinqToSqlComment { TestLinqToSqlId = item.id, text = Guid.NewGuid().ToString() };
+ g.sqlite.Insert().AppendData(comment).ExecuteAffrows();
+
+ var t1 = (from a in g.sqlite.Select().AsQueryable()
+ join b in g.sqlite.Select().AsQueryable() on a.id equals b.TestLinqToSqlId
+ select a).ToList();
+ Assert.True(t1.Any());
+ //Assert.Equal(item.id, t1[0].id);
+
+ var t2 = (from a in g.sqlite.Select().AsQueryable()
+ join b in g.sqlite.Select().AsQueryable() on a.id equals b.TestLinqToSqlId
+ select new { a.id, bid = b.id }).ToList();
+ Assert.True(t2.Any());
+ //Assert.Equal(item.id, t2[0].id);
+ //Assert.Equal(comment.id, t2[0].bid);
+
+ var t3 = (from a in g.sqlite.Select().AsQueryable()
+ join b in g.sqlite.Select().AsQueryable() on a.id equals b.TestLinqToSqlId
+ where a.id == item.id
+ select new { a.id, bid = b.id }).ToList();
+ Assert.True(t3.Any());
+ Assert.Equal(item.id, t3[0].id);
+ Assert.Equal(comment.id, t3[0].bid);
+ }
+
+ [Fact]
+ public void LeftJoin()
+ {
+ var item = new TestQueryableLinqToSql { name = Guid.NewGuid().ToString() };
+ g.sqlite.Insert().AppendData(item).ExecuteAffrows();
+ var comment = new TestQueryableLinqToSqlComment { TestLinqToSqlId = item.id, text = Guid.NewGuid().ToString() };
+ g.sqlite.Insert().AppendData(comment).ExecuteAffrows();
+
+ var t1 = (from a in g.sqlite.Select().AsQueryable()
+ join b in g.sqlite.Select().AsQueryable() on a.id equals b.TestLinqToSqlId into temp
+ from tc in temp.DefaultIfEmpty()
+ select a).ToList();
+ Assert.True(t1.Any());
+ //Assert.Equal(item.id, t1[0].id);
+
+ var t2 = (from a in g.sqlite.Select().AsQueryable()
+ join b in g.sqlite.Select().AsQueryable() on a.id equals b.TestLinqToSqlId into temp
+ from tc in temp.DefaultIfEmpty()
+ select new { a.id, bid = tc.id }).ToList();
+ Assert.True(t2.Any());
+ //Assert.Equal(item.id, t2[0].id);
+ //Assert.Equal(comment.id, t2[0].bid);
+
+ var t3 = (from a in g.sqlite.Select().AsQueryable()
+ join b in g.sqlite.Select().AsQueryable() on a.id equals b.TestLinqToSqlId into temp
+ from tc in temp.DefaultIfEmpty()
+ where a.id == item.id
+ select new { a.id, bid = tc.id }).ToList();
+ Assert.True(t3.Any());
+ Assert.Equal(item.id, t3[0].id);
+ Assert.Equal(comment.id, t3[0].bid);
+ }
+
+ [Fact]
+ public void From()
+ {
+ var item = new TestQueryableLinqToSql { name = Guid.NewGuid().ToString() };
+ g.sqlite.Insert().AppendData(item).ExecuteAffrows();
+ var comment = new TestQueryableLinqToSqlComment { TestLinqToSqlId = item.id, text = Guid.NewGuid().ToString() };
+ g.sqlite.Insert().AppendData(comment).ExecuteAffrows();
+
+ var t1 = (from a in g.sqlite.Select().AsQueryable()
+ from b in g.sqlite.Select().AsQueryable()
+ where a.id == b.TestLinqToSqlId
+ select a).ToList();
+ Assert.True(t1.Any());
+ //Assert.Equal(item.id, t1[0].id);
+
+ var t2 = (from a in g.sqlite.Select().AsQueryable()
+ from b in g.sqlite.Select().AsQueryable()
+ where a.id == b.TestLinqToSqlId
+ select new { a.id, bid = b.id }).ToList();
+ Assert.True(t2.Any());
+ //Assert.Equal(item.id, t2[0].id);
+ //Assert.Equal(comment.id, t2[0].bid);
+
+ var t3 = (from a in g.sqlite.Select().AsQueryable()
+ from b in g.sqlite.Select().AsQueryable()
+ where a.id == b.TestLinqToSqlId
+ where a.id == item.id
+ select new { a.id, bid = b.id }).ToList();
+ Assert.True(t3.Any());
+ Assert.Equal(item.id, t3[0].id);
+ Assert.Equal(comment.id, t3[0].bid);
+ }
+ }
+}
diff --git a/FreeSql.Tests/FreeSql.Tests/Queryable/QueryableTest.cs b/FreeSql.Tests/FreeSql.Tests/Queryable/QueryableTest.cs
index 8dbedf6d..acae29f2 100644
--- a/FreeSql.Tests/FreeSql.Tests/Queryable/QueryableTest.cs
+++ b/FreeSql.Tests/FreeSql.Tests/Queryable/QueryableTest.cs
@@ -17,7 +17,7 @@ using System.Diagnostics;
using System.IO;
using System.Text;
-namespace FreeSql.Tests
+namespace FreeSql.Tests.Linq
{
public class QueryableTest
{
@@ -66,6 +66,126 @@ namespace FreeSql.Tests
Assert.True(fsql.Select().AsQueryable().Any(a => a.id == sd[0].id));
Assert.False(fsql.Select().AsQueryable().Any(a => a.id == sd[0].id && sd[0].id == 0));
}
+
+ [Fact]
+ public void Max()
+ {
+ var avg = fsql.Select().AsQueryable().Max(a => a.id);
+ Assert.True(avg > 0);
+ }
+ [Fact]
+ public void Min()
+ {
+ var avg = fsql.Select().AsQueryable().Min(a => a.id);
+ Assert.True(avg > 0);
+ }
+ [Fact]
+ public void Sum()
+ {
+ var avg = fsql.Select().AsQueryable().Sum(a => a.id);
+ Assert.True(avg > 0);
+ }
+ [Fact]
+ public void Average()
+ {
+ var avg = fsql.Select().AsQueryable().Average(a => a.id);
+ Assert.True(avg > 0);
+ }
+
+ [Fact]
+ public void Contains()
+ {
+ Assert.True(fsql.Select().AsQueryable().Contains(new qt01 { id = 1 }));
+ Assert.False(fsql.Select().AsQueryable().Contains(new qt01 { id = 0 }));
+ }
+
+ [Fact]
+ public void Distinct()
+ {
+ fsql.Select().AsQueryable().Distinct().Select(a => a.name).ToList();
+ }
+
+ [Fact]
+ public void ElementAt()
+ {
+ Assert.Equal(fsql.Select().Skip(1).First().id, fsql.Select().AsQueryable().ElementAt(1).id);
+ Assert.Equal(fsql.Select().Skip(2).First().id, fsql.Select().AsQueryable().ElementAt(2).id);
+ Assert.Equal(fsql.Select().Skip(1).First().id, fsql.Select().AsQueryable().ElementAtOrDefault(1).id);
+ Assert.Equal(fsql.Select().Skip(2).First().id, fsql.Select().AsQueryable().ElementAtOrDefault(2).id);
+ }
+
+ [Fact]
+ public void First()
+ {
+ Assert.Equal(fsql.Select().First().id, fsql.Select().AsQueryable().First().id);
+ Assert.Equal(fsql.Select().First().id, fsql.Select().AsQueryable().FirstOrDefault().id);
+ }
+
+ [Fact]
+ public void Single()
+ {
+ Assert.Equal(fsql.Select().First().id, fsql.Select().AsQueryable().Single().id);
+ Assert.Equal(fsql.Select().First().id, fsql.Select().AsQueryable().SingleOrDefault().id);
+ }
+
+ [Fact]
+ public void OrderBy()
+ {
+ Assert.Equal(fsql.Select().OrderBy(a => a.id).First().id, fsql.Select().AsQueryable().OrderBy(a => a.id).Single().id);
+ Assert.Equal(fsql.Select().OrderBy(a => a.id).First().id, fsql.Select().AsQueryable().OrderBy(a => a.id).SingleOrDefault().id);
+ }
+ [Fact]
+ public void OrderByDescending()
+ {
+ Assert.Equal(fsql.Select().OrderByDescending(a => a.id).First().id, fsql.Select().AsQueryable().OrderByDescending(a => a.id).Single().id);
+ Assert.Equal(fsql.Select().OrderByDescending(a => a.id).First().id, fsql.Select().AsQueryable().OrderByDescending(a => a.id).SingleOrDefault().id);
+ }
+ [Fact]
+ public void ThenBy()
+ {
+ Assert.Equal(fsql.Select().OrderBy(a => a.id).OrderBy(a => a.id).First().id, fsql.Select().AsQueryable().OrderBy(a => a.id).OrderBy(a => a.id).Single().id);
+ Assert.Equal(fsql.Select().OrderBy(a => a.id).OrderBy(a => a.id).First().id, fsql.Select().AsQueryable().OrderBy(a => a.id).OrderBy(a => a.id).SingleOrDefault().id);
+
+ Assert.Equal(fsql.Select().OrderBy(a => a.id).OrderBy(a => a.id).First().id, fsql.Select().AsQueryable().OrderBy(a => a.id).ThenBy(a => a.id).Single().id);
+ Assert.Equal(fsql.Select().OrderBy(a => a.id).OrderBy(a => a.id).First().id, fsql.Select().AsQueryable().OrderBy(a => a.id).ThenBy(a => a.id).SingleOrDefault().id);
+ }
+ [Fact]
+ public void ThenByDescending()
+ {
+ Assert.Equal(fsql.Select().OrderBy(a => a.id).OrderByDescending(a => a.id).First().id, fsql.Select().AsQueryable().OrderBy(a => a.id).OrderByDescending(a => a.id).Single().id);
+ Assert.Equal(fsql.Select().OrderBy(a => a.id).OrderByDescending(a => a.id).First().id, fsql.Select().AsQueryable().OrderBy(a => a.id).OrderByDescending(a => a.id).SingleOrDefault().id);
+
+ Assert.Equal(fsql.Select().OrderBy(a => a.id).OrderByDescending(a => a.id).First().id, fsql.Select().AsQueryable().OrderBy(a => a.id).ThenByDescending(a => a.id).Single().id);
+ Assert.Equal(fsql.Select().OrderBy(a => a.id).OrderByDescending(a => a.id).First().id, fsql.Select().AsQueryable().OrderBy(a => a.id).ThenByDescending(a => a.id).SingleOrDefault().id);
+ }
+
+ [Fact]
+ public void Select()
+ {
+ Assert.Equal(fsql.Select().First(a => a.name), fsql.Select().AsQueryable().Select(a => a.name).Single());
+ Assert.Equal(fsql.Select().First(a => new { a.name }).name, fsql.Select().AsQueryable().Select(a => new { a.name }).Single().name);
+ }
+
+ [Fact]
+ public void Where()
+ {
+ Assert.Equal(fsql.Select().First(a => a.name), fsql.Select().AsQueryable().Select(a => a.name).Single());
+ Assert.Equal(fsql.Select().First(a => new { a.name }).name, fsql.Select().AsQueryable().Select(a => new { a.name }).Single().name);
+ }
+
+ [Fact]
+ public void Skip()
+ {
+ Assert.Equal(fsql.Select().Skip(2).First(a => a.name), fsql.Select().AsQueryable().Skip(2).Select(a => a.name).Single());
+ Assert.Equal(fsql.Select().Skip(2).First(a => new { a.name }).name, fsql.Select().AsQueryable().Skip(2).Select(a => new { a.name }).Single().name);
+ }
+
+ [Fact]
+ public void Take()
+ {
+ Assert.Equal(fsql.Select().Skip(2).First(a => a.name), fsql.Select().AsQueryable().Skip(2).Take(1).Select(a => a.name).ToList().FirstOrDefault());
+ Assert.Equal(fsql.Select().Skip(2).First(a => new { a.name }).name, fsql.Select().AsQueryable().Skip(2).Take(1).Select(a => new { a.name }).ToList().FirstOrDefault().name);
+ }
}
}
diff --git a/FreeSql.sln b/FreeSql.sln
index 37d728c5..d7236979 100644
--- a/FreeSql.sln
+++ b/FreeSql.sln
@@ -76,6 +76,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Extensions.EfCoreFl
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.All", "FreeSql.All\FreeSql.All.csproj", "{933115AD-769C-4FBE-B000-2E8CF2292377}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Extensions.Linq", "Extensions\FreeSql.Extensions.Linq\FreeSql.Extensions.Linq.csproj", "{57B3F5B0-D46A-4442-8EC6-9A9A784404B7}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -458,6 +460,18 @@ Global
{933115AD-769C-4FBE-B000-2E8CF2292377}.Release|x64.Build.0 = Release|Any CPU
{933115AD-769C-4FBE-B000-2E8CF2292377}.Release|x86.ActiveCfg = Release|Any CPU
{933115AD-769C-4FBE-B000-2E8CF2292377}.Release|x86.Build.0 = Release|Any CPU
+ {57B3F5B0-D46A-4442-8EC6-9A9A784404B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {57B3F5B0-D46A-4442-8EC6-9A9A784404B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {57B3F5B0-D46A-4442-8EC6-9A9A784404B7}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {57B3F5B0-D46A-4442-8EC6-9A9A784404B7}.Debug|x64.Build.0 = Debug|Any CPU
+ {57B3F5B0-D46A-4442-8EC6-9A9A784404B7}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {57B3F5B0-D46A-4442-8EC6-9A9A784404B7}.Debug|x86.Build.0 = Debug|Any CPU
+ {57B3F5B0-D46A-4442-8EC6-9A9A784404B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {57B3F5B0-D46A-4442-8EC6-9A9A784404B7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {57B3F5B0-D46A-4442-8EC6-9A9A784404B7}.Release|x64.ActiveCfg = Release|Any CPU
+ {57B3F5B0-D46A-4442-8EC6-9A9A784404B7}.Release|x64.Build.0 = Release|Any CPU
+ {57B3F5B0-D46A-4442-8EC6-9A9A784404B7}.Release|x86.ActiveCfg = Release|Any CPU
+ {57B3F5B0-D46A-4442-8EC6-9A9A784404B7}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -484,6 +498,7 @@ Global
{6A3A4470-7DF7-411B-AAD7-755D7A9DB5A4} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA}
{B397A761-F646-41CF-A160-AB6C05DAF2FB} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
{773D5B63-DE6E-46DB-AF16-6FB1C1352B3F} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA}
+ {57B3F5B0-D46A-4442-8EC6-9A9A784404B7} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {089687FD-5D25-40AB-BA8A-A10D1E137F98}
diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml
index 83ccee42..77e5b1ba 100644
--- a/FreeSql/FreeSql.xml
+++ b/FreeSql/FreeSql.xml
@@ -993,31 +993,6 @@
使用属性名作为字段别名
-
-
- 【linq to sql】专用方法,不建议直接使用
-
-
-
-
- 【linq to sql】专用方法,不建议直接使用
-
-
-
-
- 【linq to sql】专用方法,不建议直接使用
-
-
-
-
- 【linq to sql】专用方法,不建议直接使用
-
-
-
-
- 【linq to sql】专用方法,不建议直接使用
-
-
指定事务对象
@@ -1748,14 +1723,6 @@
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/ILinqToSql.cs b/FreeSql/Interface/Curd/ISelect/ILinqToSql.cs
deleted file mode 100644
index bba2d4e0..00000000
--- a/FreeSql/Interface/Curd/ISelect/ILinqToSql.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq.Expressions;
-using System.Text;
-
-namespace FreeSql
-{
- public interface ILinqToSql where T1 : class
- {
- ///
- /// 【linq to sql】专用方法,不建议直接使用
- ///
- ISelect Select(Expression> select) where TReturn : class;
- ///
- /// 【linq to sql】专用方法,不建议直接使用
- ///
- ISelect Join(ISelect inner, Expression> outerKeySelector, Expression> innerKeySelector, Expression> resultSelector) where TInner : class where TResult : class;
- ///
- /// 【linq to sql】专用方法,不建议直接使用
- ///
- ISelect GroupJoin(ISelect inner, Expression> outerKeySelector, Expression> innerKeySelector, Expression, TResult>> resultSelector) where TInner : class where TResult : class;
- ///
- /// 【linq to sql】专用方法,不建议直接使用
- ///
- ISelect DefaultIfEmpty();
- ///
- /// 【linq to sql】专用方法,不建议直接使用
- ///
- ISelect SelectMany(Expression>> collectionSelector, Expression> resultSelector) where TCollection : class where TResult : class;
- }
-}
diff --git a/FreeSql/Interface/Curd/ISelect/ISelect1.cs b/FreeSql/Interface/Curd/ISelect/ISelect1.cs
index a6bb4622..859b48aa 100644
--- a/FreeSql/Interface/Curd/ISelect/ISelect1.cs
+++ b/FreeSql/Interface/Curd/ISelect/ISelect1.cs
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace FreeSql
{
- public interface ISelect : ISelect0, T1>, ILinqToSql where T1 : class
+ public interface ISelect : ISelect0, T1> where T1 : class
{
#if net40
@@ -378,13 +378,5 @@ 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 8df262b1..c91ecd75 100644
--- a/FreeSql/Internal/CommonExpression.cs
+++ b/FreeSql/Internal/CommonExpression.cs
@@ -1,17 +1,18 @@
-using FreeSql.Internal.Model;
+using FreeSql.DataAnnotations;
+using FreeSql.Internal.CommonProvider;
+using FreeSql.Internal.Model;
using System;
using System.Collections;
-using System.Collections.Generic;
using System.Collections.Concurrent;
+using System.Collections.Generic;
using System.Data.Common;
+using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
-using FreeSql.DataAnnotations;
using System.Threading;
-using System.Globalization;
namespace FreeSql.Internal
{
@@ -19,8 +20,8 @@ namespace FreeSql.Internal
{
public CommonUtils _common;
- public CommonProvider.AdoProvider _ado => _adoPriv ?? (_adoPriv = _common._orm.Ado as CommonProvider.AdoProvider);
- CommonProvider.AdoProvider _adoPriv;
+ public AdoProvider _ado => _adoPriv ?? (_adoPriv = _common._orm.Ado as AdoProvider);
+ AdoProvider _adoPriv;
public CommonExpression(CommonUtils common)
{
_common = common;
@@ -692,14 +693,6 @@ namespace FreeSql.Internal
}
if (callType.FullName.StartsWith("FreeSql.ISelectGroupingAggregate`"))
{
- //if (exp3.Type == typeof(string) && exp3.Arguments.Any() && exp3.Arguments[0].NodeType == ExpressionType.Constant) {
- // switch (exp3.Method.Name) {
- // case "Sum": return $"sum({(exp3.Arguments[0] as ConstantExpression)?.Value})";
- // case "Avg": return $"avg({(exp3.Arguments[0] as ConstantExpression)?.Value})";
- // case "Max": return $"max({(exp3.Arguments[0] as ConstantExpression)?.Value})";
- // case "Min": return $"min({(exp3.Arguments[0] as ConstantExpression)?.Value})";
- // }
- //}
switch (exp3.Method.Name)
{
case "Count": return exp3.Arguments.Count == 0 ? "count(1)" : $"count({ExpressionLambdaToSql(exp3.Arguments[0], tsc)})";
@@ -819,11 +812,10 @@ namespace FreeSql.Internal
if (fsql == null) fsql = Expression.Lambda(exp3tmp).Compile().DynamicInvoke();
fsqlType = fsql?.GetType();
if (fsqlType == null) break;
- if (exp3.Method.Name != "ToList")
- fsqlType.GetField("_limit", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(fsql, 1);
- if (tsc.dbParams != null)
- fsqlType.GetField("_params", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(fsql, tsc.dbParams);
- fsqltables = fsqlType.GetField("_tables", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(fsql) as List;
+ var fsqlSelect0 = fsql as Select0Provider;
+ if (exp3.Method.Name != "ToList") fsqlSelect0._limit = 1;
+ if (tsc.dbParams != null) fsqlSelect0._params = tsc.dbParams;
+ fsqltables = fsqlSelect0._tables;
//fsqltables[0].Alias = $"{tsc._tables[0].Alias}_{fsqltables[0].Alias}";
if (fsqltables != tsc._tables)
fsqltables.AddRange(tsc._tables.Select(a => new SelectTableInfo
@@ -836,7 +828,7 @@ namespace FreeSql.Internal
}));
if (tsc.whereCascadeExpression?.Any() == true)
{
- var fsqlCascade = fsqlType.GetField("_whereCascadeExpression", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(fsql) as List;
+ var fsqlCascade = fsqlSelect0._whereCascadeExpression;
if (fsqlCascade != tsc.whereCascadeExpression)
fsqlCascade.AddRange(tsc.whereCascadeExpression);
}
@@ -1022,12 +1014,6 @@ namespace FreeSql.Internal
break;
}
}
- //var eleType = callType.GetElementType() ?? callType.GenericTypeArguments.FirstOrDefault();
- //if (eleType != null && typeof(IEnumerable<>).MakeGenericType(eleType).IsAssignableFrom(callType)) { //集合导航属性子查询
- // if (exp3.Method.Name == "Any") { //exists
-
- // }
- //}
other3Exp = ExpressionLambdaToSqlOther(exp3, tsc);
if (string.IsNullOrEmpty(other3Exp) == false) return other3Exp;
if (exp3.IsParameter() == false) return formatSql(Expression.Lambda(exp3).Compile().DynamicInvoke(), tsc.mapType, tsc.mapColumnTmp, tsc.dbParams);
@@ -1107,7 +1093,10 @@ namespace FreeSql.Internal
break;
case ExpressionType.MemberAccess:
var expStackFirstMem = expStack.First() as MemberExpression;
- if (expStackFirstMem.Expression?.NodeType == ExpressionType.Constant) firstValue = (expStackFirstMem.Expression as ConstantExpression)?.Value;
+ if (expStackFirstMem.Expression?.NodeType == ExpressionType.Constant)
+ firstValue = (expStackFirstMem.Expression as ConstantExpression)?.Value;
+ else
+ return formatSql(Expression.Lambda(exp).Compile().DynamicInvoke(), tsc.mapType, tsc.mapColumnTmp, tsc.dbParams);
break;
}
while (expStack.Any())
diff --git a/FreeSql/Internal/CommonProvider/CodeFirstProvider.cs b/FreeSql/Internal/CommonProvider/CodeFirstProvider.cs
index bd348901..619f9d23 100644
--- a/FreeSql/Internal/CommonProvider/CodeFirstProvider.cs
+++ b/FreeSql/Internal/CommonProvider/CodeFirstProvider.cs
@@ -16,7 +16,6 @@ namespace FreeSql.Internal.CommonProvider
public abstract partial class CodeFirstProvider : ICodeFirst
{
-
public IFreeSql _orm;
public CommonUtils _commonUtils;
public CommonExpression _commonExpression;
@@ -78,7 +77,7 @@ namespace FreeSql.Internal.CommonProvider
_dicSynced.TryAdd(entityType, trydic = new ConcurrentDictionary());
return trydic;
}
- internal void _dicSycedTryAdd(Type entityType, string tableName = null) =>
+ public void _dicSycedTryAdd(Type entityType, string tableName = null) =>
_dicSycedGetOrAdd(entityType).TryAdd(GetTableNameLowerOrUpper(tableName), true);
public void SyncStructure() =>
diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/QueryableProvider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/QueryableProvider.cs
deleted file mode 100644
index bf52e097..00000000
--- a/FreeSql/Internal/CommonProvider/SelectProvider/QueryableProvider.cs
+++ /dev/null
@@ -1,107 +0,0 @@
-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/Select0Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs
index 950b1383..d25664fd 100644
--- a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs
+++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs
@@ -16,33 +16,32 @@ using System.Threading.Tasks;
namespace FreeSql.Internal.CommonProvider
{
- public abstract partial class Select0Provider