- 调整 ISelect linq to sql 和 queryable 实现依赖移至 FreeSql.Extensions.Linq;#260

This commit is contained in:
28810 2020-04-10 02:28:33 +08:00
parent 98fc8baade
commit 5f98749652
21 changed files with 987 additions and 435 deletions

View File

@ -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>

View File

@ -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&lt;T1&gt; 转换为 IQueryable&lt;T1&gt;<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>

View 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&lt;T1&gt; 转换为 IQueryable&lt;T1&gt;<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;
}
}

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

Binary file not shown.

View File

@ -73,7 +73,7 @@ namespace FreeSql
public ISelect<TEntity> Where(Expression<Func<TEntity, bool>> exp) => _dbset.OrmSelectInternal(null).Where(exp); public ISelect<TEntity> Where(Expression<Func<TEntity, bool>> exp) => _dbset.OrmSelectInternal(null).Where(exp);
public ISelect<TEntity> WhereIf(bool condition, Expression<Func<TEntity, bool>> exp) => _dbset.OrmSelectInternal(null).WhereIf(condition, exp); public ISelect<TEntity> WhereIf(bool condition, Expression<Func<TEntity, bool>> exp) => _dbset.OrmSelectInternal(null).WhereIf(condition, exp);
public int Delete(Expression<Func<TEntity, bool>> predicate) public virtual int Delete(Expression<Func<TEntity, bool>> predicate)
{ {
var delete = _dbset.OrmDeleteInternal(null).Where(predicate); var delete = _dbset.OrmDeleteInternal(null).Where(predicate);
var sql = delete.ToSql(); var sql = delete.ToSql();
@ -82,12 +82,12 @@ namespace FreeSql
return affrows; return affrows;
} }
public int Delete(TEntity entity) public virtual int Delete(TEntity entity)
{ {
_dbset.Remove(entity); _dbset.Remove(entity);
return _db.SaveChanges(); return _db.SaveChanges();
} }
public int Delete(IEnumerable<TEntity> entitys) public virtual int Delete(IEnumerable<TEntity> entitys)
{ {
_dbset.RemoveRange(entitys); _dbset.RemoveRange(entitys);
return _db.SaveChanges(); return _db.SaveChanges();
@ -157,7 +157,7 @@ namespace FreeSql
return ret; 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 Find(TKey id) => _dbset.OrmSelectInternal(CheckTKeyAndReturnIdEntity(id)).ToOne();
public TEntity Get(TKey id) => Find(id); public TEntity Get(TKey id) => Find(id);
} }

View File

@ -13,7 +13,7 @@ namespace FreeSql
where TEntity : class where TEntity : class
{ {
async public Task<int> DeleteAsync(Expression<Func<TEntity, bool>> predicate) async virtual public Task<int> DeleteAsync(Expression<Func<TEntity, bool>> predicate)
{ {
var delete = _dbset.OrmDeleteInternal(null).Where(predicate); var delete = _dbset.OrmDeleteInternal(null).Where(predicate);
var sql = delete.ToSql(); var sql = delete.ToSql();
@ -22,12 +22,12 @@ namespace FreeSql
return affrows; return affrows;
} }
public Task<int> DeleteAsync(TEntity entity) public virtual Task<int> DeleteAsync(TEntity entity)
{ {
_dbset.Remove(entity); _dbset.Remove(entity);
return _db.SaveChangesAsync(); return _db.SaveChangesAsync();
} }
public Task<int> DeleteAsync(IEnumerable<TEntity> entitys) public virtual Task<int> DeleteAsync(IEnumerable<TEntity> entitys)
{ {
_dbset.RemoveRange(entitys); _dbset.RemoveRange(entitys);
return _db.SaveChangesAsync(); return _db.SaveChangesAsync();
@ -73,7 +73,7 @@ namespace FreeSql
partial class BaseRepository<TEntity, TKey> partial class BaseRepository<TEntity, TKey>
{ {
public Task<int> DeleteAsync(TKey id) => DeleteAsync(CheckTKeyAndReturnIdEntity(id)); public virtual Task<int> DeleteAsync(TKey id) => DeleteAsync(CheckTKeyAndReturnIdEntity(id));
public Task<TEntity> FindAsync(TKey id) => _dbset.OrmSelectInternal(CheckTKeyAndReturnIdEntity(id)).ToOneAsync(); public Task<TEntity> FindAsync(TKey id) => _dbset.OrmSelectInternal(CheckTKeyAndReturnIdEntity(id)).ToOneAsync();
public Task<TEntity> GetAsync(TKey id) => FindAsync(id); public Task<TEntity> GetAsync(TKey id) => FindAsync(id);
} }

View File

@ -563,8 +563,6 @@ WHERE ROWNUM < 11";
.UpdateColumns(x => new { x.Status, x.CategoryId, x.ArticleTitle }) .UpdateColumns(x => new { x.Status, x.CategoryId, x.ArticleTitle })
.ToSql(); .ToSql();
var sqldddklist = g.mysql.Select<NewsArticle>().Select(a => new NewsArticleDto { }).ToList();
var sql1111333 = g.mysql.Update<Model2>() var sql1111333 = g.mysql.Update<Model2>()
.SetSource(new Model2 { id = 1, Title = "xxx", Parent_id = 0 }) .SetSource(new Model2 { id = 1, Title = "xxx", Parent_id = 0 })
@ -608,15 +606,6 @@ WHERE ROWNUM < 11";
.ToList(); .ToList();
var ttt1 = g.mysql.Select<Model1>().Where(a => a.Childs.AsSelect().Any(b => b.Title == "111")).ToList(); var ttt1 = g.mysql.Select<Model1>().Where(a => a.Childs.AsSelect().Any(b => b.Title == "111")).ToList();
var linqto1 =
from p in g.mysql.Select<Order>()
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<TestTypeInfo>().AppendData(new TestTypeInfo { Name = "Name" + DateTime.Now.ToString("yyyyMMddHHmmss") }).ExecuteIdentity(); var testpid1 = g.mysql.Insert<TestTypeInfo>().AppendData(new TestTypeInfo { Name = "Name" + DateTime.Now.ToString("yyyyMMddHHmmss") }).ExecuteIdentity();
g.mysql.Insert<TestInfo>().AppendData(new TestInfo { Title = "Title" + DateTime.Now.ToString("yyyyMMddHHmmss"), CreateTime = DateTime.Now, TypeGuid = (int)testpid1 }).ExecuteAffrows(); g.mysql.Insert<TestInfo>().AppendData(new TestInfo { Title = "Title" + DateTime.Now.ToString("yyyyMMddHHmmss"), CreateTime = DateTime.Now, TypeGuid = (int)testpid1 }).ExecuteAffrows();

View File

@ -30,6 +30,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\Extensions\FreeSql.Extensions.LazyLoading\FreeSql.Extensions.LazyLoading.csproj" /> <ProjectReference Include="..\..\Extensions\FreeSql.Extensions.LazyLoading\FreeSql.Extensions.LazyLoading.csproj" />
<ProjectReference Include="..\..\Extensions\FreeSql.Extensions.Linq\FreeSql.Extensions.Linq.csproj" />
<ProjectReference Include="..\..\FreeSql.DbContext\FreeSql.DbContext.csproj" /> <ProjectReference Include="..\..\FreeSql.DbContext\FreeSql.DbContext.csproj" />
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" /> <ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
<ProjectReference Include="..\..\Providers\FreeSql.Provider.MsAccess\FreeSql.Provider.MsAccess.csproj" /> <ProjectReference Include="..\..\Providers\FreeSql.Provider.MsAccess\FreeSql.Provider.MsAccess.csproj" />

View File

@ -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<TestQueryableLinqToSql>().AppendData(item).ExecuteAffrows();
var t1 = (from a in g.sqlite.Select<TestQueryableLinqToSql>().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<TestQueryableLinqToSql>().AppendData(item).ExecuteAffrows();
var t1 = (from a in g.sqlite.Select<TestQueryableLinqToSql>().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<TestQueryableLinqToSql>().AppendData(item).ExecuteAffrows();
//var t1 = (from a in g.sqlite.Select<TestQueryableLinqToSql>().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<TestQueryableLinqToSql>().AppendData(item).ExecuteAffrows();
var t1 = (from a in g.sqlite.Select<TestQueryableLinqToSql>().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<TestQueryableLinqToSql>().AppendData(item).ExecuteAffrows();
var comment = new TestQueryableLinqToSqlComment { TestLinqToSqlId = item.id, text = Guid.NewGuid().ToString() };
g.sqlite.Insert<TestQueryableLinqToSqlComment>().AppendData(comment).ExecuteAffrows();
var t1 = (from a in g.sqlite.Select<TestQueryableLinqToSql>().AsQueryable()
join b in g.sqlite.Select<TestQueryableLinqToSqlComment>().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<TestQueryableLinqToSql>().AsQueryable()
join b in g.sqlite.Select<TestQueryableLinqToSqlComment>().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<TestQueryableLinqToSql>().AsQueryable()
join b in g.sqlite.Select<TestQueryableLinqToSqlComment>().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<TestQueryableLinqToSql>().AppendData(item).ExecuteAffrows();
var comment = new TestQueryableLinqToSqlComment { TestLinqToSqlId = item.id, text = Guid.NewGuid().ToString() };
g.sqlite.Insert<TestQueryableLinqToSqlComment>().AppendData(comment).ExecuteAffrows();
var t1 = (from a in g.sqlite.Select<TestQueryableLinqToSql>().AsQueryable()
join b in g.sqlite.Select<TestQueryableLinqToSqlComment>().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<TestQueryableLinqToSql>().AsQueryable()
join b in g.sqlite.Select<TestQueryableLinqToSqlComment>().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<TestQueryableLinqToSql>().AsQueryable()
join b in g.sqlite.Select<TestQueryableLinqToSqlComment>().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<TestQueryableLinqToSql>().AppendData(item).ExecuteAffrows();
var comment = new TestQueryableLinqToSqlComment { TestLinqToSqlId = item.id, text = Guid.NewGuid().ToString() };
g.sqlite.Insert<TestQueryableLinqToSqlComment>().AppendData(comment).ExecuteAffrows();
var t1 = (from a in g.sqlite.Select<TestQueryableLinqToSql>().AsQueryable()
from b in g.sqlite.Select<TestQueryableLinqToSqlComment>().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<TestQueryableLinqToSql>().AsQueryable()
from b in g.sqlite.Select<TestQueryableLinqToSqlComment>().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<TestQueryableLinqToSql>().AsQueryable()
from b in g.sqlite.Select<TestQueryableLinqToSqlComment>().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);
}
}
}

View File

@ -17,7 +17,7 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Text; using System.Text;
namespace FreeSql.Tests namespace FreeSql.Tests.Linq
{ {
public class QueryableTest public class QueryableTest
{ {
@ -66,6 +66,126 @@ namespace FreeSql.Tests
Assert.True(fsql.Select<qt01>().AsQueryable().Any(a => a.id == sd[0].id)); Assert.True(fsql.Select<qt01>().AsQueryable().Any(a => a.id == sd[0].id));
Assert.False(fsql.Select<qt01>().AsQueryable().Any(a => a.id == sd[0].id && sd[0].id == 0)); Assert.False(fsql.Select<qt01>().AsQueryable().Any(a => a.id == sd[0].id && sd[0].id == 0));
} }
[Fact]
public void Max()
{
var avg = fsql.Select<qt01>().AsQueryable().Max(a => a.id);
Assert.True(avg > 0);
}
[Fact]
public void Min()
{
var avg = fsql.Select<qt01>().AsQueryable().Min(a => a.id);
Assert.True(avg > 0);
}
[Fact]
public void Sum()
{
var avg = fsql.Select<qt01>().AsQueryable().Sum(a => a.id);
Assert.True(avg > 0);
}
[Fact]
public void Average()
{
var avg = fsql.Select<qt01>().AsQueryable().Average(a => a.id);
Assert.True(avg > 0);
}
[Fact]
public void Contains()
{
Assert.True(fsql.Select<qt01>().AsQueryable().Contains(new qt01 { id = 1 }));
Assert.False(fsql.Select<qt01>().AsQueryable().Contains(new qt01 { id = 0 }));
}
[Fact]
public void Distinct()
{
fsql.Select<qt01>().AsQueryable().Distinct().Select(a => a.name).ToList();
}
[Fact]
public void ElementAt()
{
Assert.Equal(fsql.Select<qt01>().Skip(1).First().id, fsql.Select<qt01>().AsQueryable().ElementAt(1).id);
Assert.Equal(fsql.Select<qt01>().Skip(2).First().id, fsql.Select<qt01>().AsQueryable().ElementAt(2).id);
Assert.Equal(fsql.Select<qt01>().Skip(1).First().id, fsql.Select<qt01>().AsQueryable().ElementAtOrDefault(1).id);
Assert.Equal(fsql.Select<qt01>().Skip(2).First().id, fsql.Select<qt01>().AsQueryable().ElementAtOrDefault(2).id);
}
[Fact]
public void First()
{
Assert.Equal(fsql.Select<qt01>().First().id, fsql.Select<qt01>().AsQueryable().First().id);
Assert.Equal(fsql.Select<qt01>().First().id, fsql.Select<qt01>().AsQueryable().FirstOrDefault().id);
}
[Fact]
public void Single()
{
Assert.Equal(fsql.Select<qt01>().First().id, fsql.Select<qt01>().AsQueryable().Single().id);
Assert.Equal(fsql.Select<qt01>().First().id, fsql.Select<qt01>().AsQueryable().SingleOrDefault().id);
}
[Fact]
public void OrderBy()
{
Assert.Equal(fsql.Select<qt01>().OrderBy(a => a.id).First().id, fsql.Select<qt01>().AsQueryable().OrderBy(a => a.id).Single().id);
Assert.Equal(fsql.Select<qt01>().OrderBy(a => a.id).First().id, fsql.Select<qt01>().AsQueryable().OrderBy(a => a.id).SingleOrDefault().id);
}
[Fact]
public void OrderByDescending()
{
Assert.Equal(fsql.Select<qt01>().OrderByDescending(a => a.id).First().id, fsql.Select<qt01>().AsQueryable().OrderByDescending(a => a.id).Single().id);
Assert.Equal(fsql.Select<qt01>().OrderByDescending(a => a.id).First().id, fsql.Select<qt01>().AsQueryable().OrderByDescending(a => a.id).SingleOrDefault().id);
}
[Fact]
public void ThenBy()
{
Assert.Equal(fsql.Select<qt01>().OrderBy(a => a.id).OrderBy(a => a.id).First().id, fsql.Select<qt01>().AsQueryable().OrderBy(a => a.id).OrderBy(a => a.id).Single().id);
Assert.Equal(fsql.Select<qt01>().OrderBy(a => a.id).OrderBy(a => a.id).First().id, fsql.Select<qt01>().AsQueryable().OrderBy(a => a.id).OrderBy(a => a.id).SingleOrDefault().id);
Assert.Equal(fsql.Select<qt01>().OrderBy(a => a.id).OrderBy(a => a.id).First().id, fsql.Select<qt01>().AsQueryable().OrderBy(a => a.id).ThenBy(a => a.id).Single().id);
Assert.Equal(fsql.Select<qt01>().OrderBy(a => a.id).OrderBy(a => a.id).First().id, fsql.Select<qt01>().AsQueryable().OrderBy(a => a.id).ThenBy(a => a.id).SingleOrDefault().id);
}
[Fact]
public void ThenByDescending()
{
Assert.Equal(fsql.Select<qt01>().OrderBy(a => a.id).OrderByDescending(a => a.id).First().id, fsql.Select<qt01>().AsQueryable().OrderBy(a => a.id).OrderByDescending(a => a.id).Single().id);
Assert.Equal(fsql.Select<qt01>().OrderBy(a => a.id).OrderByDescending(a => a.id).First().id, fsql.Select<qt01>().AsQueryable().OrderBy(a => a.id).OrderByDescending(a => a.id).SingleOrDefault().id);
Assert.Equal(fsql.Select<qt01>().OrderBy(a => a.id).OrderByDescending(a => a.id).First().id, fsql.Select<qt01>().AsQueryable().OrderBy(a => a.id).ThenByDescending(a => a.id).Single().id);
Assert.Equal(fsql.Select<qt01>().OrderBy(a => a.id).OrderByDescending(a => a.id).First().id, fsql.Select<qt01>().AsQueryable().OrderBy(a => a.id).ThenByDescending(a => a.id).SingleOrDefault().id);
}
[Fact]
public void Select()
{
Assert.Equal(fsql.Select<qt01>().First(a => a.name), fsql.Select<qt01>().AsQueryable().Select(a => a.name).Single());
Assert.Equal(fsql.Select<qt01>().First(a => new { a.name }).name, fsql.Select<qt01>().AsQueryable().Select(a => new { a.name }).Single().name);
}
[Fact]
public void Where()
{
Assert.Equal(fsql.Select<qt01>().First(a => a.name), fsql.Select<qt01>().AsQueryable().Select(a => a.name).Single());
Assert.Equal(fsql.Select<qt01>().First(a => new { a.name }).name, fsql.Select<qt01>().AsQueryable().Select(a => new { a.name }).Single().name);
}
[Fact]
public void Skip()
{
Assert.Equal(fsql.Select<qt01>().Skip(2).First(a => a.name), fsql.Select<qt01>().AsQueryable().Skip(2).Select(a => a.name).Single());
Assert.Equal(fsql.Select<qt01>().Skip(2).First(a => new { a.name }).name, fsql.Select<qt01>().AsQueryable().Skip(2).Select(a => new { a.name }).Single().name);
}
[Fact]
public void Take()
{
Assert.Equal(fsql.Select<qt01>().Skip(2).First(a => a.name), fsql.Select<qt01>().AsQueryable().Skip(2).Take(1).Select(a => a.name).ToList().FirstOrDefault());
Assert.Equal(fsql.Select<qt01>().Skip(2).First(a => new { a.name }).name, fsql.Select<qt01>().AsQueryable().Skip(2).Take(1).Select(a => new { a.name }).ToList().FirstOrDefault().name);
}
} }
} }

View File

@ -76,6 +76,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Extensions.EfCoreFl
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.All", "FreeSql.All\FreeSql.All.csproj", "{933115AD-769C-4FBE-B000-2E8CF2292377}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.All", "FreeSql.All\FreeSql.All.csproj", "{933115AD-769C-4FBE-B000-2E8CF2292377}"
EndProject 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 Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU 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|x64.Build.0 = Release|Any CPU
{933115AD-769C-4FBE-B000-2E8CF2292377}.Release|x86.ActiveCfg = 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 {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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -484,6 +498,7 @@ Global
{6A3A4470-7DF7-411B-AAD7-755D7A9DB5A4} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA} {6A3A4470-7DF7-411B-AAD7-755D7A9DB5A4} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA}
{B397A761-F646-41CF-A160-AB6C05DAF2FB} = {2A381C57-2697-427B-9F10-55DA11FD02E4} {B397A761-F646-41CF-A160-AB6C05DAF2FB} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
{773D5B63-DE6E-46DB-AF16-6FB1C1352B3F} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA} {773D5B63-DE6E-46DB-AF16-6FB1C1352B3F} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA}
{57B3F5B0-D46A-4442-8EC6-9A9A784404B7} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {089687FD-5D25-40AB-BA8A-A10D1E137F98} SolutionGuid = {089687FD-5D25-40AB-BA8A-A10D1E137F98}

View File

@ -993,31 +993,6 @@
使用属性名作为字段别名 使用属性名作为字段别名
</summary> </summary>
</member> </member>
<member name="M:FreeSql.ILinqToSql`1.Select``1(System.Linq.Expressions.Expression{System.Func{`0,``0}})">
<summary>
【linq to sql】专用方法不建议直接使用
</summary>
</member>
<member name="M:FreeSql.ILinqToSql`1.Join``3(FreeSql.ISelect{``0},System.Linq.Expressions.Expression{System.Func{`0,``1}},System.Linq.Expressions.Expression{System.Func{``0,``1}},System.Linq.Expressions.Expression{System.Func{`0,``0,``2}})">
<summary>
【linq to sql】专用方法不建议直接使用
</summary>
</member>
<member name="M:FreeSql.ILinqToSql`1.GroupJoin``3(FreeSql.ISelect{``0},System.Linq.Expressions.Expression{System.Func{`0,``1}},System.Linq.Expressions.Expression{System.Func{``0,``1}},System.Linq.Expressions.Expression{System.Func{`0,FreeSql.ISelect{``0},``2}})">
<summary>
【linq to sql】专用方法不建议直接使用
</summary>
</member>
<member name="M:FreeSql.ILinqToSql`1.DefaultIfEmpty">
<summary>
【linq to sql】专用方法不建议直接使用
</summary>
</member>
<member name="M:FreeSql.ILinqToSql`1.SelectMany``2(System.Linq.Expressions.Expression{System.Func{`0,FreeSql.ISelect{``0}}},System.Linq.Expressions.Expression{System.Func{`0,``0,``1}})">
<summary>
【linq to sql】专用方法不建议直接使用
</summary>
</member>
<member name="M:FreeSql.ISelect0`2.WithTransaction(System.Data.Common.DbTransaction)"> <member name="M:FreeSql.ISelect0`2.WithTransaction(System.Data.Common.DbTransaction)">
<summary> <summary>
指定事务对象 指定事务对象
@ -1748,14 +1723,6 @@
<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&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}})"> <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")

View File

@ -1,31 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;
namespace FreeSql
{
public interface ILinqToSql<T1> where T1 : class
{
/// <summary>
/// 【linq to sql】专用方法不建议直接使用
/// </summary>
ISelect<TReturn> Select<TReturn>(Expression<Func<T1, TReturn>> select) where TReturn : class;
/// <summary>
/// 【linq to sql】专用方法不建议直接使用
/// </summary>
ISelect<TResult> Join<TInner, TKey, TResult>(ISelect<TInner> inner, Expression<Func<T1, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<T1, TInner, TResult>> resultSelector) where TInner : class where TResult : class;
/// <summary>
/// 【linq to sql】专用方法不建议直接使用
/// </summary>
ISelect<TResult> GroupJoin<TInner, TKey, TResult>(ISelect<TInner> inner, Expression<Func<T1, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<T1, ISelect<TInner>, TResult>> resultSelector) where TInner : class where TResult : class;
/// <summary>
/// 【linq to sql】专用方法不建议直接使用
/// </summary>
ISelect<T1> DefaultIfEmpty();
/// <summary>
/// 【linq to sql】专用方法不建议直接使用
/// </summary>
ISelect<TResult> SelectMany<TCollection, TResult>(Expression<Func<T1, ISelect<TCollection>>> collectionSelector, Expression<Func<T1, TCollection, TResult>> resultSelector) where TCollection : class where TResult : class;
}
}

View File

@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace FreeSql namespace FreeSql
{ {
public interface ISelect<T1> : ISelect0<ISelect<T1>, T1>, ILinqToSql<T1> where T1 : class public interface ISelect<T1> : ISelect0<ISelect<T1>, T1> where T1 : class
{ {
#if net40 #if net40
@ -378,13 +378,5 @@ 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&lt;T1&gt; 转换为 IQueryable&lt;T1&gt;<para></para>
/// 此方法主要用于扩展比如abp IRepository GetAll() 接口方法需要返回 IQueryable 对象<para></para>
/// 注意IQueryable 方法污染较为严重,请尽量避免此转换
/// </summary>
/// <returns></returns>
IQueryable<T1> AsQueryable();
} }
} }

View File

@ -1,17 +1,18 @@
using FreeSql.Internal.Model; using FreeSql.DataAnnotations;
using FreeSql.Internal.CommonProvider;
using FreeSql.Internal.Model;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data.Common; using System.Data.Common;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using FreeSql.DataAnnotations;
using System.Threading; using System.Threading;
using System.Globalization;
namespace FreeSql.Internal namespace FreeSql.Internal
{ {
@ -19,8 +20,8 @@ namespace FreeSql.Internal
{ {
public CommonUtils _common; public CommonUtils _common;
public CommonProvider.AdoProvider _ado => _adoPriv ?? (_adoPriv = _common._orm.Ado as CommonProvider.AdoProvider); public AdoProvider _ado => _adoPriv ?? (_adoPriv = _common._orm.Ado as AdoProvider);
CommonProvider.AdoProvider _adoPriv; AdoProvider _adoPriv;
public CommonExpression(CommonUtils common) public CommonExpression(CommonUtils common)
{ {
_common = common; _common = common;
@ -692,14 +693,6 @@ namespace FreeSql.Internal
} }
if (callType.FullName.StartsWith("FreeSql.ISelectGroupingAggregate`")) 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) switch (exp3.Method.Name)
{ {
case "Count": return exp3.Arguments.Count == 0 ? "count(1)" : $"count({ExpressionLambdaToSql(exp3.Arguments[0], tsc)})"; 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(); if (fsql == null) fsql = Expression.Lambda(exp3tmp).Compile().DynamicInvoke();
fsqlType = fsql?.GetType(); fsqlType = fsql?.GetType();
if (fsqlType == null) break; if (fsqlType == null) break;
if (exp3.Method.Name != "ToList") var fsqlSelect0 = fsql as Select0Provider;
fsqlType.GetField("_limit", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(fsql, 1); if (exp3.Method.Name != "ToList") fsqlSelect0._limit = 1;
if (tsc.dbParams != null) if (tsc.dbParams != null) fsqlSelect0._params = tsc.dbParams;
fsqlType.GetField("_params", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(fsql, tsc.dbParams); fsqltables = fsqlSelect0._tables;
fsqltables = fsqlType.GetField("_tables", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(fsql) as List<SelectTableInfo>;
//fsqltables[0].Alias = $"{tsc._tables[0].Alias}_{fsqltables[0].Alias}"; //fsqltables[0].Alias = $"{tsc._tables[0].Alias}_{fsqltables[0].Alias}";
if (fsqltables != tsc._tables) if (fsqltables != tsc._tables)
fsqltables.AddRange(tsc._tables.Select(a => new SelectTableInfo fsqltables.AddRange(tsc._tables.Select(a => new SelectTableInfo
@ -836,7 +828,7 @@ namespace FreeSql.Internal
})); }));
if (tsc.whereCascadeExpression?.Any() == true) if (tsc.whereCascadeExpression?.Any() == true)
{ {
var fsqlCascade = fsqlType.GetField("_whereCascadeExpression", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(fsql) as List<LambdaExpression>; var fsqlCascade = fsqlSelect0._whereCascadeExpression;
if (fsqlCascade != tsc.whereCascadeExpression) if (fsqlCascade != tsc.whereCascadeExpression)
fsqlCascade.AddRange(tsc.whereCascadeExpression); fsqlCascade.AddRange(tsc.whereCascadeExpression);
} }
@ -1022,12 +1014,6 @@ namespace FreeSql.Internal
break; 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); other3Exp = ExpressionLambdaToSqlOther(exp3, tsc);
if (string.IsNullOrEmpty(other3Exp) == false) return other3Exp; if (string.IsNullOrEmpty(other3Exp) == false) return other3Exp;
if (exp3.IsParameter() == false) return formatSql(Expression.Lambda(exp3).Compile().DynamicInvoke(), tsc.mapType, tsc.mapColumnTmp, tsc.dbParams); 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; break;
case ExpressionType.MemberAccess: case ExpressionType.MemberAccess:
var expStackFirstMem = expStack.First() as MemberExpression; 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; break;
} }
while (expStack.Any()) while (expStack.Any())

View File

@ -16,7 +16,6 @@ namespace FreeSql.Internal.CommonProvider
public abstract partial class CodeFirstProvider : ICodeFirst public abstract partial class CodeFirstProvider : ICodeFirst
{ {
public IFreeSql _orm; public IFreeSql _orm;
public CommonUtils _commonUtils; public CommonUtils _commonUtils;
public CommonExpression _commonExpression; public CommonExpression _commonExpression;
@ -78,7 +77,7 @@ namespace FreeSql.Internal.CommonProvider
_dicSynced.TryAdd(entityType, trydic = new ConcurrentDictionary<string, bool>()); _dicSynced.TryAdd(entityType, trydic = new ConcurrentDictionary<string, bool>());
return trydic; return trydic;
} }
internal void _dicSycedTryAdd(Type entityType, string tableName = null) => public void _dicSycedTryAdd(Type entityType, string tableName = null) =>
_dicSycedGetOrAdd(entityType).TryAdd(GetTableNameLowerOrUpper(tableName), true); _dicSycedGetOrAdd(entityType).TryAdd(GetTableNameLowerOrUpper(tableName), true);
public void SyncStructure<TEntity>() => public void SyncStructure<TEntity>() =>

View File

@ -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<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

@ -16,33 +16,32 @@ using System.Threading.Tasks;
namespace FreeSql.Internal.CommonProvider namespace FreeSql.Internal.CommonProvider
{ {
public abstract partial class Select0Provider<TSelect, T1> : ISelect0<TSelect, T1> where TSelect : class where T1 : class public abstract partial class Select0Provider
{ {
public int _limit, _skip;
protected int _limit, _skip; public string _select = "SELECT ", _orderby, _groupby, _having;
protected string _select = "SELECT ", _orderby, _groupby, _having; public StringBuilder _where = new StringBuilder();
protected StringBuilder _where = new StringBuilder(); public List<DbParameter> _params = new List<DbParameter>();
protected List<DbParameter> _params = new List<DbParameter>(); public List<SelectTableInfo> _tables = new List<SelectTableInfo>();
internal protected List<SelectTableInfo> _tables = new List<SelectTableInfo>(); public List<Func<Type, string, string>> _tableRules = new List<Func<Type, string, string>>();
protected List<Func<Type, string, string>> _tableRules = new List<Func<Type, string, string>>(); public Func<Type, string, string> _aliasRule;
protected Func<Type, string, string> _aliasRule; public string _tosqlAppendContent;
protected string _tosqlAppendContent; public StringBuilder _join = new StringBuilder();
protected StringBuilder _join = new StringBuilder(); public IFreeSql _orm;
internal protected IFreeSql _orm; public CommonUtils _commonUtils;
protected CommonUtils _commonUtils; public CommonExpression _commonExpression;
protected CommonExpression _commonExpression; public DbTransaction _transaction;
protected DbTransaction _transaction; public DbConnection _connection;
protected DbConnection _connection; public Action<object> _trackToList;
internal protected Action<object> _trackToList; public List<Action<object>> _includeToList = new List<Action<object>>();
internal protected List<Action<object>> _includeToList = new List<Action<object>>();
#if net40 #if net40
#else #else
protected List<Func<object, Task>> _includeToListAsync = new List<Func<object, Task>>(); public List<Func<object, Task>> _includeToListAsync = new List<Func<object, Task>>();
#endif #endif
protected bool _distinct; public bool _distinct;
protected Expression _selectExpression; public Expression _selectExpression;
protected List<LambdaExpression> _whereCascadeExpression = new List<LambdaExpression>(); public List<LambdaExpression> _whereCascadeExpression = new List<LambdaExpression>();
protected List<GlobalFilter.Item> _whereGlobalFilter; public List<GlobalFilter.Item> _whereGlobalFilter;
int _disposeCounter; int _disposeCounter;
~Select0Provider() ~Select0Provider()
@ -64,24 +63,25 @@ namespace FreeSql.Internal.CommonProvider
_whereGlobalFilter = _orm.GlobalFilter.GetFilters(); _whereGlobalFilter = _orm.GlobalFilter.GetFilters();
_whereCascadeExpression.AddRange(_whereGlobalFilter.Select(a => a.Where)); _whereCascadeExpression.AddRange(_whereGlobalFilter.Select(a => a.Where));
} }
public static void CopyData(Select0Provider<TSelect, T1> from, object to, ReadOnlyCollection<ParameterExpression> lambParms)
public static void CopyData(Select0Provider from, Select0Provider to, ReadOnlyCollection<ParameterExpression> lambParms)
{ {
var toType = to?.GetType(); if (to == null) return;
if (toType == null) return; to._limit = from._limit;
toType.GetField("_limit", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._limit); to._skip = from._skip;
toType.GetField("_skip", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._skip); to._select = from._select;
toType.GetField("_select", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._select); to._orderby = from._orderby;
toType.GetField("_orderby", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._orderby); to._groupby = from._groupby;
toType.GetField("_groupby", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._groupby); to._having = from._having;
toType.GetField("_having", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._having); to._where = new StringBuilder().Append(from._where.ToString());
toType.GetField("_where", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new StringBuilder().Append(from._where.ToString())); to._params = new List<DbParameter>(from._params.ToArray());
toType.GetField("_params", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<DbParameter>(from._params.ToArray()));
if (lambParms == null) if (lambParms == null)
toType.GetField("_tables", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<SelectTableInfo>(from._tables.ToArray())); to._tables = new List<SelectTableInfo>(from._tables.ToArray());
else else
{ {
var findedIndexs = new List<int>(); var findedIndexs = new List<int>();
var _multiTables = toType.GetField("_tables", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(to) as List<SelectTableInfo>; var _multiTables = to._tables;
_multiTables[0] = from._tables[0]; _multiTables[0] = from._tables[0];
for (var a = 1; a < lambParms.Count; a++) for (var a = 1; a < lambParms.Count; a++)
{ {
@ -103,26 +103,29 @@ namespace FreeSql.Internal.CommonProvider
_multiTables.Add(from._tables[a]); _multiTables.Add(from._tables[a]);
} }
} }
toType.GetField("_tableRules", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<Func<Type, string, string>>(from._tableRules.ToArray())); to._tableRules = new List<Func<Type, string, string>>(from._tableRules.ToArray());
toType.GetField("_aliasRule", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._aliasRule); to._aliasRule = from._aliasRule;
toType.GetField("_join", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new StringBuilder().Append(from._join.ToString())); to._join = new StringBuilder().Append(from._join.ToString());
//toType.GetField("_orm", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._orm); //to._orm = from._orm;
//toType.GetField("_commonUtils", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._commonUtils); //to._commonUtils = from._commonUtils;
//toType.GetField("_commonExpression", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._commonExpression); //to._commonExpression = from._commonExpression;
toType.GetField("_transaction", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._transaction); to._transaction = from._transaction;
toType.GetField("_connection", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._connection); to._connection = from._connection;
toType.GetField("_trackToList", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._trackToList); to._trackToList = from._trackToList;
toType.GetField("_includeToList", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<Action<object>>(from._includeToList.ToArray())); to._includeToList = new List<Action<object>>(from._includeToList.ToArray());
#if net40 #if net40
#else #else
toType.GetField("_includeToListAsync", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<Func<object, Task>>(from._includeToListAsync.ToArray())); to._includeToListAsync = new List<Func<object, Task>>(from._includeToListAsync.ToArray());
#endif #endif
toType.GetField("_distinct", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._distinct); to._distinct = from._distinct;
toType.GetField("_selectExpression", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._selectExpression); to._selectExpression = from._selectExpression;
toType.GetField("_whereCascadeExpression", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<LambdaExpression>(from._whereCascadeExpression.ToArray())); to._whereCascadeExpression = new List<LambdaExpression>(from._whereCascadeExpression.ToArray());
toType.GetField("_whereGlobalFilter", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<GlobalFilter.Item>(from._whereGlobalFilter.ToArray())); to._whereGlobalFilter = new List<GlobalFilter.Item>(from._whereGlobalFilter.ToArray());
} }
}
public abstract partial class Select0Provider<TSelect, T1> : Select0Provider, ISelect0<TSelect, T1> where TSelect : class where T1 : class
{
public Select0Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) public Select0Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
{ {
_orm = orm; _orm = orm;
@ -1082,7 +1085,7 @@ namespace FreeSql.Internal.CommonProvider
protected TMember InternalMin<TMember>(Expression exp) => this.ToList<TMember>($"min({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}").Min(); protected TMember InternalMin<TMember>(Expression exp) => this.ToList<TMember>($"min({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}").Min();
protected decimal InternalSum(Expression exp) => this.ToList<decimal>($"sum({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}").Sum(); protected decimal InternalSum(Expression exp) => this.ToList<decimal>($"sum({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)}){_commonUtils.FieldAsAlias("as1")}").Sum();
protected ISelectGrouping<TKey, TValue> InternalGroupBy<TKey, TValue>(Expression columns) public ISelectGrouping<TKey, TValue> InternalGroupBy<TKey, TValue>(Expression columns)
{ {
var map = new ReadAnonymousTypeInfo(); var map = new ReadAnonymousTypeInfo();
var field = new StringBuilder(); var field = new StringBuilder();
@ -1093,7 +1096,7 @@ namespace FreeSql.Internal.CommonProvider
this.GroupBy(sql.Length > 0 ? sql.Substring(2) : null); this.GroupBy(sql.Length > 0 ? sql.Substring(2) : null);
return new SelectGroupingProvider<TKey, TValue>(_orm, this, map, sql, _commonExpression, _tables); return new SelectGroupingProvider<TKey, TValue>(_orm, this, map, sql, _commonExpression, _tables);
} }
protected TSelect InternalJoin(Expression exp, SelectTableInfoType joinType) public TSelect InternalJoin(Expression exp, SelectTableInfoType joinType)
{ {
_commonExpression.ExpressionJoinLambda(_tables, joinType, exp, null, _whereCascadeExpression); _commonExpression.ExpressionJoinLambda(_tables, joinType, exp, null, _whereCascadeExpression);
return this as TSelect; return this as TSelect;
@ -1109,7 +1112,7 @@ namespace FreeSql.Internal.CommonProvider
protected TSelect InternalOrderBy(Expression column) => this.OrderBy(_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true, null)); protected TSelect InternalOrderBy(Expression column) => this.OrderBy(_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true, null));
protected TSelect InternalOrderByDescending(Expression column) => this.OrderBy($"{_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true, null)} DESC"); protected TSelect InternalOrderByDescending(Expression column) => this.OrderBy($"{_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true, null)} DESC");
protected List<TReturn> InternalToList<TReturn>(Expression select) => this.ToListMapReader<TReturn>(this.GetExpressionField(select)); public List<TReturn> InternalToList<TReturn>(Expression select) => this.ToListMapReader<TReturn>(this.GetExpressionField(select));
protected string InternalToSql<TReturn>(Expression select, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex) protected string InternalToSql<TReturn>(Expression select, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex)
{ {
var af = this.GetExpressionField(select, fieldAlias); var af = this.GetExpressionField(select, fieldAlias);
@ -1151,7 +1154,7 @@ namespace FreeSql.Internal.CommonProvider
return this.ToListMapReader<TReturn>(new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null)).FirstOrDefault(); return this.ToListMapReader<TReturn>(new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null)).FirstOrDefault();
} }
protected TSelect InternalWhere(Expression exp) => exp == null ? this as TSelect : this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp, null, _whereCascadeExpression, _params)); public TSelect InternalWhere(Expression exp) => exp == null ? this as TSelect : this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp, null, _whereCascadeExpression, _params));
#endregion #endregion
#if net40 #if net40

View File

@ -111,15 +111,15 @@ namespace FreeSql.Internal.CommonProvider
return this.InternalAvg(column?.Body); return this.InternalAvg(column?.Body);
} }
public abstract ISelect<T1, T2> From<T2>(Expression<Func<ISelectFromExpression<T1>, T2, ISelectFromExpression<T1>>> exp) where T2 : class;// { this.InternalFrom(exp); var ret = new Select3Provider<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; } public abstract ISelect<T1, T2> From<T2>(Expression<Func<ISelectFromExpression<T1>, T2, ISelectFromExpression<T1>>> exp) where T2 : class;
public abstract ISelect<T1, T2, T3> From<T2, T3>(Expression<Func<ISelectFromExpression<T1>, T2, T3, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class;// { this.InternalFrom(exp); var ret = new Select3Provider<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; } public abstract ISelect<T1, T2, T3> From<T2, T3>(Expression<Func<ISelectFromExpression<T1>, T2, T3, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class;
public abstract ISelect<T1, T2, T3, T4> From<T2, T3, T4>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class;// { this.InternalFrom(exp); var ret = new Select4Provider<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; } public abstract ISelect<T1, T2, T3, T4> From<T2, T3, T4>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class;
public abstract ISelect<T1, T2, T3, T4, T5> From<T2, T3, T4, T5>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class;// { this.InternalFrom(exp); var ret = new Select5Provider<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; } public abstract ISelect<T1, T2, T3, T4, T5> From<T2, T3, T4, T5>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class;
public abstract ISelect<T1, T2, T3, T4, T5, T6> From<T2, T3, T4, T5, T6>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class;// { this.InternalFrom(exp); var ret = new Select6Provider<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; } public abstract ISelect<T1, T2, T3, T4, T5, T6> From<T2, T3, T4, T5, T6>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class;
public abstract ISelect<T1, T2, T3, T4, T5, T6, T7> From<T2, T3, T4, T5, T6, T7>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class;// { this.InternalFrom(exp); var ret = new Select7Provider<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; } public abstract ISelect<T1, T2, T3, T4, T5, T6, T7> From<T2, T3, T4, T5, T6, T7>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class;
public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8> From<T2, T3, T4, T5, T6, T7, T8>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class;// { this.InternalFrom(exp); var ret = new Select8Provider<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; } public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8> From<T2, T3, T4, T5, T6, T7, T8>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class;
public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> From<T2, T3, T4, T5, T6, T7, T8, T9>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class;// { this.InternalFrom(exp); var ret = new Select9Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; } public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> From<T2, T3, T4, T5, T6, T7, T8, T9>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class;
public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> From<T2, T3, T4, T5, T6, T7, T8, T9, T10>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class;// { this.InternalFrom(exp); var ret = new Select10Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, exp?.Parameters); return ret; } public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> From<T2, T3, T4, T5, T6, T7, T8, T9, T10>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class;
public ISelectGrouping<TKey, T1> GroupBy<TKey>(Expression<Func<T1, TKey>> columns) public ISelectGrouping<TKey, T1> GroupBy<TKey>(Expression<Func<T1, TKey>> columns)
{ {
@ -132,41 +132,48 @@ namespace FreeSql.Internal.CommonProvider
{ {
if (column == null) return default(TMember); if (column == null) return default(TMember);
_tables[0].Parameter = column.Parameters[0]; _tables[0].Parameter = column.Parameters[0];
return this.InternalMax<TMember>(column?.Body); return this.InternalMax<TMember>(column.Body);
} }
public TMember Min<TMember>(Expression<Func<T1, TMember>> column) public TMember Min<TMember>(Expression<Func<T1, TMember>> column)
{ {
if (column == null) return default(TMember); if (column == null) return default(TMember);
_tables[0].Parameter = column.Parameters[0]; _tables[0].Parameter = column.Parameters[0];
return this.InternalMin<TMember>(column?.Body); return this.InternalMin<TMember>(column.Body);
}
public void OrderByReflection(LambdaExpression column, bool isDescending)
{
if (column == null) return;
_tables[0].Parameter = column.Parameters[0];
if (isDescending) this.InternalOrderByDescending(column.Body);
else this.InternalOrderBy(column.Body);
} }
public ISelect<T1> OrderBy<TMember>(Expression<Func<T1, TMember>> column) => this.OrderBy(true, column); public ISelect<T1> OrderBy<TMember>(Expression<Func<T1, TMember>> column) => this.OrderBy(true, column);
public ISelect<T1> OrderBy<TMember>(bool condition, Expression<Func<T1, TMember>> column) public ISelect<T1> OrderBy<TMember>(bool condition, Expression<Func<T1, TMember>> column)
{ {
if (condition == false || column == null) return this; if (condition == false || column == null) return this;
_tables[0].Parameter = column.Parameters[0]; _tables[0].Parameter = column.Parameters[0];
return this.InternalOrderBy(column?.Body); return this.InternalOrderBy(column.Body);
} }
public ISelect<T1> OrderByDescending<TMember>(Expression<Func<T1, TMember>> column) => this.OrderByDescending(true, column); public ISelect<T1> OrderByDescending<TMember>(Expression<Func<T1, TMember>> column) => this.OrderByDescending(true, column);
public ISelect<T1> OrderByDescending<TMember>(bool condition, Expression<Func<T1, TMember>> column) public ISelect<T1> OrderByDescending<TMember>(bool condition, Expression<Func<T1, TMember>> column)
{ {
if (condition == false || column == null) return this; if (condition == false || column == null) return this;
_tables[0].Parameter = column.Parameters[0]; _tables[0].Parameter = column.Parameters[0];
return this.InternalOrderByDescending(column?.Body); return this.InternalOrderByDescending(column.Body);
} }
public decimal Sum<TMember>(Expression<Func<T1, TMember>> column) public decimal Sum<TMember>(Expression<Func<T1, TMember>> column)
{ {
if (column == null) return default(decimal); if (column == null) return default(decimal);
_tables[0].Parameter = column.Parameters[0]; _tables[0].Parameter = column.Parameters[0];
return this.InternalSum(column?.Body); return this.InternalSum(column.Body);
} }
public List<TReturn> ToList<TReturn>(Expression<Func<T1, TReturn>> select) public List<TReturn> ToList<TReturn>(Expression<Func<T1, TReturn>> select)
{ {
if (select == null) return this.InternalToList<TReturn>(select?.Body); if (select == null) return this.InternalToList<TReturn>(select?.Body);
_tables[0].Parameter = select.Parameters[0]; _tables[0].Parameter = select.Parameters[0];
return this.InternalToList<TReturn>(select?.Body); return this.InternalToList<TReturn>(select.Body);
} }
public List<TDto> ToList<TDto>() => ToList(GetToListDtoSelector<TDto>()); public List<TDto> ToList<TDto>() => ToList(GetToListDtoSelector<TDto>());
@ -177,89 +184,6 @@ namespace FreeSql.Internal.CommonProvider
_tables[0].Parameter ?? Expression.Parameter(typeof(T1), "a")); _tables[0].Parameter ?? Expression.Parameter(typeof(T1), "a"));
} }
#region linq to sql
public ISelect<TReturn> Select<TReturn>(Expression<Func<T1, TReturn>> select) where TReturn : class
{
if (typeof(TReturn) == typeof(T1)) return this as ISelect<TReturn>;
_tables[0].Parameter = select.Parameters[0];
_selectExpression = select.Body;
if (_orm.CodeFirst.IsAutoSyncStructure)
(_orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(TReturn)); //._dicSyced.TryAdd(typeof(TReturn), true);
var ret = _orm.Select<TReturn>();
Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, null);
return ret;
}
public ISelect<TResult> Join<TInner, TKey, TResult>(ISelect<TInner> inner, Expression<Func<T1, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<T1, TInner, TResult>> resultSelector) where TInner : class where TResult : class
{
_tables[0].Parameter = resultSelector.Parameters[0];
_commonExpression.ExpressionLambdaToSql(outerKeySelector, new CommonExpression.ExpTSC { _tables = _tables });
this.InternalJoin(Expression.Lambda<Func<T1, TInner, bool>>(
Expression.Equal(outerKeySelector.Body, innerKeySelector.Body),
new[] { outerKeySelector.Parameters[0], innerKeySelector.Parameters[0] }
), SelectTableInfoType.InnerJoin);
if (typeof(TResult) == typeof(T1)) return this as ISelect<TResult>;
_selectExpression = resultSelector.Body;
if (_orm.CodeFirst.IsAutoSyncStructure)
(_orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(TResult)); //._dicSyced.TryAdd(typeof(TResult), true);
var ret = _orm.Select<TResult>() as Select1Provider<TResult>;
Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, null);
return ret;
}
public ISelect<TResult> GroupJoin<TInner, TKey, TResult>(ISelect<TInner> inner, Expression<Func<T1, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<T1, ISelect<TInner>, TResult>> resultSelector) where TInner : class where TResult : class
{
_tables[0].Parameter = resultSelector.Parameters[0];
_commonExpression.ExpressionLambdaToSql(outerKeySelector, new CommonExpression.ExpTSC { _tables = _tables });
this.InternalJoin(Expression.Lambda<Func<T1, TInner, bool>>(
Expression.Equal(outerKeySelector.Body, innerKeySelector.Body),
new[] { outerKeySelector.Parameters[0], innerKeySelector.Parameters[0] }
), SelectTableInfoType.InnerJoin);
if (typeof(TResult) == typeof(T1)) return this as ISelect<TResult>;
_selectExpression = resultSelector.Body;
if (_orm.CodeFirst.IsAutoSyncStructure)
(_orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(TResult)); //._dicSyced.TryAdd(typeof(TResult), true);
var ret = _orm.Select<TResult>() as Select1Provider<TResult>;
Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, null);
return ret;
}
public ISelect<TResult> SelectMany<TCollection, TResult>(Expression<Func<T1, ISelect<TCollection>>> collectionSelector, Expression<Func<T1, TCollection, TResult>> resultSelector) where TCollection : class where TResult : class
{
SelectTableInfo find = null;
if (collectionSelector.Body.NodeType == ExpressionType.Call)
{
var callExp = collectionSelector.Body as MethodCallExpression;
if (callExp.Method.Name == "DefaultIfEmpty" && callExp.Object.Type.GetGenericArguments().Any())
{
find = _tables.Where((a, idx) => idx > 0 && a.Type == SelectTableInfoType.InnerJoin && a.Table.Type == callExp.Object.Type.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 = _commonUtils.GetTableByEntity(typeof(TCollection));
if (tb == null) throw new Exception($"SelectMany 错误的类型:{typeof(TCollection).FullName}");
_tables.Add(new SelectTableInfo { Alias = resultSelector.Parameters[1].Name, AliasInit = resultSelector.Parameters[1].Name, Parameter = resultSelector.Parameters[1], Table = tb, Type = SelectTableInfoType.From });
}
if (typeof(TResult) == typeof(T1)) return this as ISelect<TResult>;
_selectExpression = resultSelector.Body;
if (_orm.CodeFirst.IsAutoSyncStructure)
(_orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(TResult)); //._dicSyced.TryAdd(typeof(TResult), true);
var ret = _orm.Select<TResult>() as Select1Provider<TResult>;
Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, null);
return ret;
}
public ISelect<T1> DefaultIfEmpty()
{
return this;
}
#endregion
public DataTable ToDataTable<TReturn>(Expression<Func<T1, TReturn>> select) public DataTable ToDataTable<TReturn>(Expression<Func<T1, TReturn>> select)
{ {
if (select == null) return this.InternalToDataTable(select?.Body); if (select == null) return this.InternalToDataTable(select?.Body);
@ -1083,8 +1007,6 @@ 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)

View File

@ -1,5 +1,6 @@
using FreeSql.Internal.Model; using FreeSql.Internal.Model;
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
@ -9,14 +10,15 @@ using System.Threading.Tasks;
namespace FreeSql.Internal.CommonProvider namespace FreeSql.Internal.CommonProvider
{ {
public class SelectGroupingProvider<TKey, TValue> : ISelectGrouping<TKey, TValue> public class SelectGroupingProvider
{ {
internal IFreeSql _orm; public IFreeSql _orm;
internal object _select; public object _select;
internal ReadAnonymousTypeInfo _map; public ReadAnonymousTypeInfo _map;
internal string _field; public string _field;
internal CommonExpression _comonExp; public CommonExpression _comonExp;
internal List<SelectTableInfo> _tables; public List<SelectTableInfo> _tables;
public SelectGroupingProvider(IFreeSql orm, object select, ReadAnonymousTypeInfo map, string field, CommonExpression comonExp, List<SelectTableInfo> tables) public SelectGroupingProvider(IFreeSql orm, object select, ReadAnonymousTypeInfo map, string field, CommonExpression comonExp, List<SelectTableInfo> tables)
{ {
_orm = orm; _orm = orm;
@ -27,7 +29,7 @@ namespace FreeSql.Internal.CommonProvider
_tables = tables; _tables = tables;
} }
string getSelectGroupingMapString(Expression[] members) public string getSelectGroupingMapString(Expression[] members)
{ {
if (members.Any() == false) return _map.DbField; if (members.Any() == false) return _map.DbField;
var parentName = ((members.FirstOrDefault() as MemberExpression)?.Expression as MemberExpression)?.Member.Name; var parentName = ((members.FirstOrDefault() as MemberExpression)?.Expression as MemberExpression)?.Member.Name;
@ -85,59 +87,45 @@ namespace FreeSql.Internal.CommonProvider
return null; return null;
} }
public ISelectGrouping<TKey, TValue> Having(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, bool>> exp) public void InternalHaving(Expression exp)
{ {
var sql = _comonExp.ExpressionWhereLambda(null, exp, getSelectGroupingMapString, null, null); var sql = _comonExp.ExpressionWhereLambda(null, exp, getSelectGroupingMapString, null, null);
var method = _select.GetType().GetMethod("Having", new[] { typeof(string), typeof(object) }); var method = _select.GetType().GetMethod("Having", new[] { typeof(string), typeof(object) });
method.Invoke(_select, new object[] { sql, null }); method.Invoke(_select, new object[] { sql, null });
return this;
} }
public void InternalOrderBy(Expression exp, bool isDescending)
public ISelectGrouping<TKey, TValue> OrderBy<TMember>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TMember>> column)
{ {
var sql = _comonExp.ExpressionWhereLambda(null, column, getSelectGroupingMapString, null, null); var sql = _comonExp.ExpressionWhereLambda(null, exp, getSelectGroupingMapString, null, null);
var method = _select.GetType().GetMethod("OrderBy", new[] { typeof(string), typeof(object) }); var method = _select.GetType().GetMethod("OrderBy", new[] { typeof(string), typeof(object) });
method.Invoke(_select, new object[] { sql, null }); method.Invoke(_select, new object[] { isDescending ? $"{sql} DESC" : sql, null });
return this;
} }
public object InternalToList(Expression select, Type elementType, bool isAsync)
public ISelectGrouping<TKey, TValue> OrderByDescending<TMember>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TMember>> column)
{
var sql = _comonExp.ExpressionWhereLambda(null, column, getSelectGroupingMapString, null, null);
var method = _select.GetType().GetMethod("OrderBy", new[] { typeof(string), typeof(object) });
method.Invoke(_select, new object[] { $"{sql} DESC", null });
return this;
}
public List<TReturn> Select<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select) => ToList(select);
public List<TReturn> ToList<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select)
{ {
var map = new ReadAnonymousTypeInfo(); var map = new ReadAnonymousTypeInfo();
var field = new StringBuilder(); var field = new StringBuilder();
var index = 0; var index = 0;
_comonExp.ReadAnonymousField(null, field, map, ref index, select, getSelectGroupingMapString, null, false); _comonExp.ReadAnonymousField(null, field, map, ref index, select, getSelectGroupingMapString, null, false);
if (map.Childs.Any() == false && map.MapType == null) map.MapType = typeof(TReturn); if (map.Childs.Any() == false && map.MapType == null) map.MapType = elementType;
var method = _select.GetType().GetMethod("ToListMapReader", BindingFlags.Instance | BindingFlags.NonPublic); var method = _select.GetType().GetMethod(isAsync ? "ToListMapReaderAsync" : "ToListMapReader", BindingFlags.Instance | BindingFlags.NonPublic);
method = method.MakeGenericMethod(typeof(TReturn)); method = method.MakeGenericMethod(elementType);
return method.Invoke(_select, new object[] { new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null) }) as List<TReturn>; return method.Invoke(_select, new object[] { new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null) });
} }
public Dictionary<TKey, TElement> ToDictionary<TElement>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TElement>> elementSelector) public IEnumerable<KeyValuePair<object, object>> InternalToKeyValuePairs(Expression elementSelector, Type elementType)
{ {
var map = new ReadAnonymousTypeInfo(); var map = new ReadAnonymousTypeInfo();
var field = new StringBuilder(); var field = new StringBuilder();
var index = 0; var index = 0;
_comonExp.ReadAnonymousField(null, field, map, ref index, elementSelector, getSelectGroupingMapString, null, false); _comonExp.ReadAnonymousField(null, field, map, ref index, elementSelector, getSelectGroupingMapString, null, false);
if (map.Childs.Any() == false && map.MapType == null) map.MapType = typeof(TElement); if (map.Childs.Any() == false && map.MapType == null) map.MapType = elementType;
var method = _select.GetType().GetMethod("ToListMapReaderPrivate", BindingFlags.Instance | BindingFlags.NonPublic); var method = _select.GetType().GetMethod("ToListMapReaderPrivate", BindingFlags.Instance | BindingFlags.NonPublic);
method = method.MakeGenericMethod(typeof(TElement)); method = method.MakeGenericMethod(elementType);
var otherAf = new ReadAnonymousTypeOtherInfo(_field, _map, new List<object>()); var otherAf = new ReadAnonymousTypeOtherInfo(_field, _map, new List<object>());
var values = method.Invoke(_select, new object[] { new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null), new[] { otherAf } }) as List<TElement>; var values = method.Invoke(_select, new object[] { new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null), new[] { otherAf } }) as IList;
return otherAf.retlist.Select((a, b) => new KeyValuePair<TKey, TElement>((TKey)a, values[b])).ToDictionary(a => a.Key, a => a.Value); return otherAf.retlist.Select((a, b) => new KeyValuePair<object, object>(a, values[b]));
} }
public string InternalToSql(Expression select, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex)
public string ToSql<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex)
{ {
var map = new ReadAnonymousTypeInfo(); var map = new ReadAnonymousTypeInfo();
var field = new StringBuilder(); var field = new StringBuilder();
@ -147,6 +135,14 @@ namespace FreeSql.Internal.CommonProvider
var method = _select.GetType().GetMethod("ToSql", new[] { typeof(string) }); var method = _select.GetType().GetMethod("ToSql", new[] { typeof(string) });
return method.Invoke(_select, new object[] { field.Length > 0 ? field.Remove(0, 2).ToString() : null }) as string; return method.Invoke(_select, new object[] { field.Length > 0 ? field.Remove(0, 2).ToString() : null }) as string;
} }
}
public class SelectGroupingProvider<TKey, TValue> : SelectGroupingProvider, ISelectGrouping<TKey, TValue>
{
public SelectGroupingProvider(IFreeSql orm, object select, ReadAnonymousTypeInfo map, string field, CommonExpression comonExp, List<SelectTableInfo> tables)
:base(orm, select, map, field, comonExp, tables) { }
public string ToSql<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex) => InternalToSql(select, fieldAlias);
public string ToSql(string field) public string ToSql(string field)
{ {
if (string.IsNullOrEmpty(field)) if (string.IsNullOrEmpty(field))
@ -163,7 +159,6 @@ namespace FreeSql.Internal.CommonProvider
return this; return this;
} }
public ISelectGrouping<TKey, TValue> Offset(int offset) => this.Skip(offset); public ISelectGrouping<TKey, TValue> Offset(int offset) => this.Skip(offset);
public ISelectGrouping<TKey, TValue> Limit(int limit) public ISelectGrouping<TKey, TValue> Limit(int limit)
{ {
var method = _select.GetType().GetMethod("Limit", new[] { typeof(int) }); var method = _select.GetType().GetMethod("Limit", new[] { typeof(int) });
@ -171,7 +166,6 @@ namespace FreeSql.Internal.CommonProvider
return this; return this;
} }
public ISelectGrouping<TKey, TValue> Take(int limit) => this.Limit(limit); public ISelectGrouping<TKey, TValue> Take(int limit) => this.Limit(limit);
public ISelectGrouping<TKey, TValue> Page(int pageNumber, int pageSize) public ISelectGrouping<TKey, TValue> Page(int pageNumber, int pageSize)
{ {
var method = _select.GetType().GetMethod("Page", new[] { typeof(int), typeof(int) }); var method = _select.GetType().GetMethod("Page", new[] { typeof(int), typeof(int) });
@ -186,22 +180,31 @@ namespace FreeSql.Internal.CommonProvider
return this; return this;
} }
public ISelectGrouping<TKey, TValue> Having(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, bool>> exp)
{
InternalHaving(exp);
return this;
}
public ISelectGrouping<TKey, TValue> OrderBy<TMember>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TMember>> column)
{
InternalOrderBy(column, false);
return this;
}
public ISelectGrouping<TKey, TValue> OrderByDescending<TMember>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TMember>> column)
{
InternalOrderBy(column, true);
return this;
}
public List<TReturn> Select<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select) => ToList(select);
public List<TReturn> ToList<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select) => InternalToList(select, typeof(TReturn), false) as List<TReturn>;
public Dictionary<TKey, TElement> ToDictionary<TElement>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TElement>> elementSelector) => InternalToKeyValuePairs(elementSelector, typeof(TElement)).ToDictionary(a => (TKey)a.Key, a => (TElement)a.Value);
#if net40 #if net40
#else #else
async public Task<long> CountAsync() => long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync($"select count(1) from ({this.ToSql($"1{_comonExp._common.FieldAsAlias("as1")}")}) fta")), out var trylng) ? trylng : default(long); async public Task<long> CountAsync() => long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync($"select count(1) from ({this.ToSql($"1{_comonExp._common.FieldAsAlias("as1")}")}) fta")), out var trylng) ? trylng : default(long);
public Task<List<TReturn>> ToListAsync<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select) public Task<List<TReturn>> ToListAsync<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select) => InternalToList(select, typeof(TReturn), true) as Task<List<TReturn>>;
{
var map = new ReadAnonymousTypeInfo();
var field = new StringBuilder();
var index = 0;
_comonExp.ReadAnonymousField(null, field, map, ref index, select, getSelectGroupingMapString, null, false);
if (map.Childs.Any() == false && map.MapType == null) map.MapType = typeof(TReturn);
var method = _select.GetType().GetMethod("ToListMapReaderAsync", BindingFlags.Instance | BindingFlags.NonPublic);
method = method.MakeGenericMethod(typeof(TReturn));
return method.Invoke(_select, new object[] { new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null) }) as Task<List<TReturn>>;
}
async public Task<Dictionary<TKey, TElement>> ToDictionaryAsync<TElement>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TElement>> elementSelector) async public Task<Dictionary<TKey, TElement>> ToDictionaryAsync<TElement>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TElement>> elementSelector)
{ {
var map = new ReadAnonymousTypeInfo(); var map = new ReadAnonymousTypeInfo();