28810 7c42c67797 - 修复 MapType 属性的表达式解析 数组.Contains 得到是映射之前的值 bug;
- 修复 MapType 属性 与 IncludeMany 变异功能未映射处理的 bug;
2019-11-17 17:14:00 +08:00

971 lines
59 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using FreeSql.Extensions.EntityUtil;
using FreeSql.Internal.Model;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace FreeSql.Internal.CommonProvider
{
public abstract class Select1Provider<T1> : Select0Provider<ISelect<T1>, T1>, ISelect<T1>
where T1 : class
{
public Select1Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere)
{
_whereGlobalFilter = _orm.GlobalFilter.GetFilters();
_whereCascadeExpression.AddRange(_whereGlobalFilter.Select(a => a.Where));
}
protected ISelect<T1> InternalFrom(LambdaExpression lambdaExp)
{
if (lambdaExp != null)
{
for (var a = 1; a < lambdaExp.Parameters.Count; a++)
{
var tb = _commonUtils.GetTableByEntity(lambdaExp.Parameters[a].Type);
if (tb == null) throw new ArgumentException($"{lambdaExp.Parameters[a].Name} 类型错误");
_tables.Add(new SelectTableInfo { Table = tb, Alias = lambdaExp.Parameters[a].Name, On = null, Type = SelectTableInfoType.From });
}
}
var exp = lambdaExp?.Body;
if (exp?.NodeType == ExpressionType.Call)
{
var expCall = exp as MethodCallExpression;
var stockCall = new Stack<MethodCallExpression>();
while (expCall != null)
{
stockCall.Push(expCall);
expCall = expCall.Object as MethodCallExpression;
}
while (stockCall.Any())
{
expCall = stockCall.Pop();
switch (expCall.Method.Name)
{
case "Where": this.InternalWhere(expCall.Arguments[0]); break;
case "WhereIf":
var whereIfCond = _commonExpression.ExpressionSelectColumn_MemberAccess(null, null, SelectTableInfoType.From, expCall.Arguments[0], false, null);
if (whereIfCond == "1" || whereIfCond == "'t'")
this.InternalWhere(expCall.Arguments[1]);
break;
case "OrderBy":
if (expCall.Arguments.Count == 2 && expCall.Arguments[0].Type == typeof(bool))
{
var ifcond = _commonExpression.ExpressionSelectColumn_MemberAccess(null, null, SelectTableInfoType.From, expCall.Arguments[0], false, null);
if (ifcond == "1" || ifcond == "'t'")
this.InternalOrderBy(expCall.Arguments.LastOrDefault());
break;
}
this.InternalOrderBy(expCall.Arguments.LastOrDefault());
break;
case "OrderByDescending":
if (expCall.Arguments.Count == 2 && expCall.Arguments[0].Type == typeof(bool))
{
var ifcond = _commonExpression.ExpressionSelectColumn_MemberAccess(null, null, SelectTableInfoType.From, expCall.Arguments[0], false, null);
if (ifcond == "1" || ifcond == "'t'")
this.InternalOrderByDescending(expCall.Arguments.LastOrDefault());
break;
}
this.InternalOrderByDescending(expCall.Arguments.LastOrDefault());
break;
case "LeftJoin": this.InternalJoin(expCall.Arguments[0], SelectTableInfoType.LeftJoin); break;
case "InnerJoin": this.InternalJoin(expCall.Arguments[0], SelectTableInfoType.InnerJoin); break;
case "RightJoin": this.InternalJoin(expCall.Arguments[0], SelectTableInfoType.RightJoin); break;
default: throw new NotImplementedException($"未实现 {expCall.Method.Name}");
}
}
}
return this;
}
public ISelect<T1> As(string alias)
{
var oldAs = _tables.First().Alias;
var newAs = string.IsNullOrEmpty(alias) ? "a" : alias;
if (oldAs != newAs)
{
_tables.First().Alias = newAs;
var wh = _where.ToString();
_where.Replace($" {oldAs}.", $" {newAs}.");
}
return this;
}
public TMember Avg<TMember>(Expression<Func<T1, TMember>> column)
{
if (column == null) return default(TMember);
_tables[0].Parameter = column.Parameters[0];
return this.InternalAvg<TMember>(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, 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, 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, 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, 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, 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, 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, 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, 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 ISelectGrouping<TKey, T1> GroupBy<TKey>(Expression<Func<T1, TKey>> columns)
{
if (columns == null) return this.InternalGroupBy<TKey, T1>(columns);
_tables[0].Parameter = columns.Parameters[0];
return this.InternalGroupBy<TKey, T1>(columns);
}
public TMember Max<TMember>(Expression<Func<T1, TMember>> column)
{
if (column == null) return default(TMember);
_tables[0].Parameter = column.Parameters[0];
return this.InternalMax<TMember>(column?.Body);
}
public TMember Min<TMember>(Expression<Func<T1, TMember>> column)
{
if (column == null) return default(TMember);
_tables[0].Parameter = column.Parameters[0];
return this.InternalMin<TMember>(column?.Body);
}
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)
{
if (condition == false || column == null) return this;
_tables[0].Parameter = column.Parameters[0];
return this.InternalOrderBy(column?.Body);
}
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)
{
if (condition == false || column == null) return this;
_tables[0].Parameter = column.Parameters[0];
return this.InternalOrderByDescending(column?.Body);
}
public TMember Sum<TMember>(Expression<Func<T1, TMember>> column)
{
if (column == null) return default(TMember);
_tables[0].Parameter = column.Parameters[0];
return this.InternalSum<TMember>(column?.Body);
}
public List<TReturn> ToList<TReturn>(Expression<Func<T1, TReturn>> select)
{
if (select == null) return this.InternalToList<TReturn>(select?.Body);
_tables[0].Parameter = select.Parameters[0];
return this.InternalToList<TReturn>(select?.Body);
}
public List<TDto> ToList<TDto>() => ToList(GetToListDtoSelector<TDto>());
Expression<Func<T1, TDto>> GetToListDtoSelector<TDto>()
{
var ctor = typeof(TDto).GetConstructor(new Type[0]);
return Expression.Lambda<Func<T1, TDto>>(Expression.New(ctor),
_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;
(_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;
(_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;
(_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;
(_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)
{
if (select == null) return this.InternalToDataTable(select?.Body);
_tables[0].Parameter = select.Parameters[0];
return this.InternalToDataTable(select?.Body);
}
public string ToSql<TReturn>(Expression<Func<T1, TReturn>> select)
{
if (select == null) return this.InternalToSql<TReturn>(select?.Body);
_tables[0].Parameter = select.Parameters[0];
return this.InternalToSql<TReturn>(select?.Body);
}
public TReturn ToAggregate<TReturn>(Expression<Func<ISelectGroupingAggregate<T1>, TReturn>> select)
{
if (select == null) return default(TReturn);
_tables[0].Parameter = select.Parameters[0];
return this.InternalToAggregate<TReturn>(select?.Body);
}
public ISelect<T1> Where(Expression<Func<T1, bool>> exp) => WhereIf(true, exp);
public ISelect<T1> WhereIf(bool condition, Expression<Func<T1, bool>> exp)
{
if (condition == false || exp == null) return this;
_tables[0].Parameter = exp.Parameters[0];
return this.InternalWhere(exp?.Body);
}
public ISelect<T1> Where<T2>(Expression<Func<T1, T2, bool>> exp) where T2 : class
{
if (exp == null) return this;
_tables[0].Parameter = exp.Parameters[0];
return this.InternalWhere(exp?.Body);
}
public ISelect<T1> Where<T2>(Expression<Func<T2, bool>> exp) where T2 : class
{
if (exp == null) return this;
//_tables[0].Parameter = exp.Parameters[0];
return this.InternalWhere(exp?.Body);
}
public ISelect<T1> Where<T2, T3>(Expression<Func<T1, T2, T3, bool>> exp) where T2 : class where T3 : class
{
if (exp == null) return this;
_tables[0].Parameter = exp.Parameters[0];
return this.InternalWhere(exp?.Body);
}
public ISelect<T1> Where<T2, T3, T4>(Expression<Func<T1, T2, T3, T4, bool>> exp) where T2 : class where T3 : class where T4 : class
{
if (exp == null) return this;
_tables[0].Parameter = exp.Parameters[0];
return this.InternalWhere(exp?.Body);
}
public ISelect<T1> Where<T2, T3, T4, T5>(Expression<Func<T1, T2, T3, T4, T5, bool>> exp) where T2 : class where T3 : class where T4 : class where T5 : class
{
if (exp == null) return this;
_tables[0].Parameter = exp.Parameters[0];
return this.InternalWhere(exp?.Body);
}
public ISelect<T1> WhereDynamic(object dywhere) => this.Where(_commonUtils.WhereObject(_tables.First().Table, $"{_tables.First().Alias}.", dywhere));
public ISelect<T1> WhereCascade(Expression<Func<T1, bool>> exp)
{
if (exp != null) _whereCascadeExpression.Add(exp);
return this;
}
public bool Any(Expression<Func<T1, bool>> exp) => this.Where(exp).Any();
public TReturn ToOne<TReturn>(Expression<Func<T1, TReturn>> select) => this.Limit(1).ToList(select).FirstOrDefault();
public TDto ToOne<TDto>() => this.Limit(1).ToList<TDto>().FirstOrDefault();
public TReturn First<TReturn>(Expression<Func<T1, TReturn>> select) => this.ToOne(select);
public TDto First<TDto>() => this.ToOne<TDto>();
public override List<T1> ToList(bool includeNestedMembers = false) => base.ToList(_isIncluded || includeNestedMembers);
bool _isIncluded = false;
public ISelect<T1> Include<TNavigate>(Expression<Func<T1, TNavigate>> navigateSelector) where TNavigate : class
{
var expBody = navigateSelector?.Body;
if (expBody == null) return this;
var tb = _commonUtils.GetTableByEntity(expBody.Type);
if (tb == null) throw new Exception("Include 参数类型错误");
_isIncluded = true;
_commonExpression.ExpressionWhereLambda(_tables, Expression.MakeMemberAccess(expBody, tb.Properties[tb.ColumnsByCs.First().Value.CsName]), null, null);
return this;
}
static (ParameterExpression param, List<MemberExpression> members) GetExpressionStack(Expression exp)
{
Expression tmpExp = exp;
ParameterExpression param = null;
var members = new List<MemberExpression>();
var isbreak = false;
while (isbreak == false)
{
switch (tmpExp.NodeType)
{
case ExpressionType.MemberAccess:
var memExp = tmpExp as MemberExpression;
tmpExp = memExp.Expression;
members.Add(memExp);
continue;
case ExpressionType.Parameter:
param = tmpExp as ParameterExpression;
isbreak = true;
break;
default:
throw new Exception($"表达式错误,它不是连续的 MemberAccess 类型:{exp}");
}
}
if (param == null) throw new Exception($"表达式错误,它的顶级对象不是 ParameterExpression{exp}");
return (param, members);
}
static MethodInfo GetEntityValueWithPropertyNameMethod = typeof(EntityUtilExtensions).GetMethod("GetEntityValueWithPropertyName");
static ConcurrentDictionary<Type, ConcurrentDictionary<string, MethodInfo>> _dicTypeMethod = new ConcurrentDictionary<Type, ConcurrentDictionary<string, MethodInfo>>();
public ISelect<T1> IncludeMany<TNavigate>(Expression<Func<T1, IEnumerable<TNavigate>>> navigateSelector, Action<ISelect<TNavigate>> then = null) where TNavigate : class
{
var throwNavigateSelector = new Exception("IncludeMany 参数1 类型错误,表达式类型应该为 MemberAccess");
var expBody = navigateSelector?.Body;
if (expBody == null) return this;
MethodCallExpression whereExp = null;
int takeNumber = 0;
while (expBody.NodeType == ExpressionType.Call)
{
throwNavigateSelector = new Exception($"IncludeMany {nameof(navigateSelector)} 参数类型错误,表达式格式应该是 a.collections.Take(1).Where(c => c.aid == a.id)");
var callExp = (expBody as MethodCallExpression);
switch (callExp.Method.Name)
{
case "Where":
whereExp = callExp;
break;
case "Take": takeNumber = int.Parse((callExp.Arguments[1] as ConstantExpression)?.Value?.ToString() ?? "0"); break;
default: throw throwNavigateSelector;
}
expBody = callExp.Object ?? callExp.Arguments.FirstOrDefault();
}
if (expBody.NodeType != ExpressionType.MemberAccess) throw throwNavigateSelector;
var collMem = expBody as MemberExpression;
var (membersParam, members) = GetExpressionStack(collMem.Expression);
var tb = _commonUtils.GetTableByEntity(collMem.Expression.Type);
if (tb == null) throw throwNavigateSelector;
var tbNav = _commonUtils.GetTableByEntity(typeof(TNavigate));
if (tbNav == null) throw new Exception($"类型 {typeof(TNavigate).FullName} 错误,不能使用 IncludeMany");
if (collMem.Expression.NodeType != ExpressionType.Parameter)
_commonExpression.ExpressionWhereLambda(_tables, Expression.MakeMemberAccess(collMem.Expression, tb.Properties[tb.ColumnsByCs.First().Value.CsName]), null, null);
TableRef tbref = null;
var tbrefOneToManyColumns = new List<List<MemberExpression>>(); //临时 OneToMany 三个表关联,第三个表需要前两个表确定
if (whereExp == null)
{
tbref = tb.GetTableRef(collMem.Member.Name, true);
}
else
{
//处理临时关系映射
tbref = new TableRef
{
RefType = TableRefType.OneToMany,
Property = tb.Properties[collMem.Member.Name],
RefEntityType = tbNav.Type
};
foreach (var whereExpArg in whereExp.Arguments)
{
if (whereExpArg.NodeType != ExpressionType.Lambda) continue;
var whereExpArgLamb = whereExpArg as LambdaExpression;
Action<Expression> actWeiParse = null;
actWeiParse = expOrg =>
{
var binaryExp = expOrg as BinaryExpression;
if (binaryExp == null) throw throwNavigateSelector;
switch (binaryExp.NodeType)
{
case ExpressionType.AndAlso:
actWeiParse(binaryExp.Left);
actWeiParse(binaryExp.Right);
break;
case ExpressionType.Equal:
Expression leftExp = binaryExp.Left;
Expression rightExp = binaryExp.Right;
while (leftExp.NodeType == ExpressionType.Convert) leftExp = (leftExp as UnaryExpression)?.Operand;
while (rightExp.NodeType == ExpressionType.Convert) rightExp = (rightExp as UnaryExpression)?.Operand;
var leftP1MemberExp = leftExp as MemberExpression;
var rightP1MemberExp = rightExp as MemberExpression;
if (leftP1MemberExp == null || rightP1MemberExp == null) throw throwNavigateSelector;
if (leftP1MemberExp.Expression == whereExpArgLamb.Parameters[0])
{
var (rightMembersParam, rightMembers) = GetExpressionStack(rightP1MemberExp.Expression);
if (rightMembersParam != membersParam) throw throwNavigateSelector;
var isCollMemEquals = rightMembers.Count == members.Count;
if (isCollMemEquals)
{
for (var l = 0; l < members.Count; l++)
if (members[l].Member != rightMembers[l].Member)
{
isCollMemEquals = false;
break;
}
}
if (isCollMemEquals)
{
tbref.Columns.Add(tb.ColumnsByCs[rightP1MemberExp.Member.Name]);
tbrefOneToManyColumns.Add(null);
}
else
{
var tmpTb = _commonUtils.GetTableByEntity(rightP1MemberExp.Expression.Type);
if (tmpTb == null) throw throwNavigateSelector;
tbref.Columns.Add(tmpTb.ColumnsByCs[rightP1MemberExp.Member.Name]);
tbrefOneToManyColumns.Add(rightMembers);
}
tbref.RefColumns.Add(tbNav.ColumnsByCs[leftP1MemberExp.Member.Name]);
return;
}
if (rightP1MemberExp.Expression == whereExpArgLamb.Parameters[0])
{
var (leftMembersParam, leftMembers) = GetExpressionStack(leftP1MemberExp.Expression);
if (leftMembersParam != membersParam) throw throwNavigateSelector;
var isCollMemEquals = leftMembers.Count == members.Count;
if (isCollMemEquals)
{
for (var l = 0; l < members.Count; l++)
if (members[l].Member != leftMembers[l].Member)
{
isCollMemEquals = false;
break;
}
}
if (isCollMemEquals)
{
tbref.Columns.Add(tb.ColumnsByCs[leftP1MemberExp.Member.Name]);
tbrefOneToManyColumns.Add(null);
}
else
{
var tmpTb = _commonUtils.GetTableByEntity(leftP1MemberExp.Expression.Type);
if (tmpTb == null) throw throwNavigateSelector;
tbref.Columns.Add(tmpTb.ColumnsByCs[leftP1MemberExp.Member.Name]);
tbrefOneToManyColumns.Add(leftMembers);
}
tbref.RefColumns.Add(tbNav.ColumnsByCs[rightP1MemberExp.Member.Name]);
return;
}
throw throwNavigateSelector;
default: throw throwNavigateSelector;
}
};
actWeiParse(whereExpArgLamb.Body);
break;
}
if (tbref.Columns.Any() == false) throw throwNavigateSelector;
}
_includeToList.Add(listObj =>
{
var list = listObj as List<T1>;
if (list == null) return;
if (list.Any() == false) return;
if (tbref.Columns.Any() == false) return;
var t1parm = Expression.Parameter(typeof(T1));
Expression membersExp = t1parm;
foreach (var mem in members) membersExp = Expression.MakeMemberAccess(membersExp, mem.Member);
members.Clear();
var listValueExp = Expression.Parameter(typeof(List<TNavigate>), "listValue");
var setListValue = Expression.Lambda<Action<T1, List<TNavigate>>>(
Expression.Assign(
Expression.MakeMemberAccess(membersExp, collMem.Member),
Expression.TypeAs(listValueExp, collMem.Type)
), t1parm, listValueExp).Compile();
var returnTarget = Expression.Label(typeof(object));
var propertyNameExp = Expression.Parameter(typeof(string), "propertyName");
var getListValue1 = Expression.Lambda<Func<T1, string, object>>(
Expression.Block(
Expression.Return(returnTarget, Expression.Call(null, GetEntityValueWithPropertyNameMethod, Expression.Constant(_orm), Expression.Constant(membersExp.Type), membersExp, propertyNameExp)),
Expression.Label(returnTarget, Expression.Default(typeof(object)))
), t1parm, propertyNameExp).Compile();
var getListValue2 = new List<Func<T1, string, object>>();
for (var j = 0; j < tbrefOneToManyColumns.Count; j++)
{
if (tbrefOneToManyColumns[j] == null)
{
getListValue2.Add(null);
continue;
}
Expression tbrefOneToManyColumnsMembers = t1parm;
foreach (var mem in tbrefOneToManyColumns[j]) tbrefOneToManyColumnsMembers = Expression.MakeMemberAccess(tbrefOneToManyColumnsMembers, mem.Member);
tbrefOneToManyColumns[j].Clear();
getListValue2.Add(Expression.Lambda<Func<T1, string, object>>(
Expression.Block(
Expression.Return(returnTarget, Expression.Call(null, GetEntityValueWithPropertyNameMethod, Expression.Constant(_orm), Expression.Constant(tbrefOneToManyColumnsMembers.Type), tbrefOneToManyColumnsMembers, propertyNameExp)),
Expression.Label(returnTarget, Expression.Default(typeof(object)))
), t1parm, propertyNameExp).Compile());
}
tbrefOneToManyColumns.Clear();
Func<T1, string, int, object> getListValue = (item, propName, colIndex) =>
{
if (getListValue2.Any() && getListValue2[colIndex] != null) return getListValue2[colIndex](item, propName);
return getListValue1(item, propName);
};
foreach (var item in list)
setListValue(item, null);
var subSelect = _orm.Select<TNavigate>().DisableGlobalFilter().WithConnection(_connection).WithTransaction(_transaction).TrackToList(_trackToList) as Select1Provider<TNavigate>;
if (_tableRules?.Any() == true)
foreach (var tr in _tableRules) subSelect.AsTable(tr);
if (_whereCascadeExpression.Any())
subSelect._whereCascadeExpression.AddRange(_whereCascadeExpression.ToArray());
then?.Invoke(subSelect);
var subSelectT1Alias = subSelect._tables[0].Alias;
var oldWhere = subSelect._where.ToString();
if (oldWhere.StartsWith(" AND ")) oldWhere = oldWhere.Remove(0, 5);
switch (tbref.RefType)
{
case TableRefType.OneToMany:
if (true)
{
var subList = new List<TNavigate>();
var tbref2 = _commonUtils.GetTableByEntity(tbref.RefEntityType);
Func<Dictionary<string, bool>> getWhereDic = () =>
{
var sbDic = new Dictionary<string, bool>();
for (var y = 0; y < list.Count; y++)
{
var sbWhereOne = new StringBuilder();
sbWhereOne.Append("(");
for (var z = 0; z < tbref.Columns.Count; z++)
{
if (z > 0) sbWhereOne.Append(" AND ");
sbWhereOne.Append(_commonUtils.FormatSql($"{subSelectT1Alias}.{_commonUtils.QuoteSqlName(tbref.RefColumns[z].Attribute.Name)}={{0}}", Utils.GetDataReaderValue(tbref.RefColumns[z].Attribute.MapType, getListValue(list[y], tbref.Columns[z].CsName, z))));
}
sbWhereOne.Append(")");
var whereOne = sbWhereOne.ToString();
sbWhereOne.Clear();
if (sbDic.ContainsKey(whereOne) == false) sbDic.Add(whereOne, true);
}
return sbDic;
};
if (takeNumber > 0)
{
var af = subSelect.GetAllFieldExpressionTreeLevelAll();
var sbSql = new StringBuilder();
var sbDic = getWhereDic();
foreach (var sbd in sbDic)
{
subSelect._where.Clear();
subSelect.Where(sbd.Key).Where(oldWhere).Limit(takeNumber);
sbSql.Append("\r\nUNION ALL\r\nselect * from (").Append(subSelect.ToSql(af.Field)).Append(") ftb");
}
sbSql.Remove(0, 13);
if (sbDic.Count == 1) sbSql.Remove(0, 15).Remove(sbSql.Length - 5, 5);
sbDic.Clear();
subList = subSelect.ToListAfPrivate(sbSql.ToString(), af, null);
sbSql.Clear();
}
else
{
subSelect._where.Clear();
if (tbref.Columns.Count == 1)
{
var arrExp = Expression.NewArrayInit(tbref.RefColumns[0].CsType,
list.Select(a => getListValue(a, tbref.Columns[0].CsName, 0)).Distinct()
.Select(a => Expression.Constant(Utils.GetDataReaderValue(tbref.RefColumns[0].CsType, a), tbref.RefColumns[0].CsType)).ToArray());
var otmExpParm1 = Expression.Parameter(typeof(TNavigate), "a");
var containsMethod = _dicTypeMethod.GetOrAdd(tbref.RefColumns[0].CsType, et => new ConcurrentDictionary<string, MethodInfo>()).GetOrAdd("Contains", mn =>
typeof(Enumerable).GetMethods().Where(a => a.Name == mn).First()).MakeGenericMethod(tbref.RefColumns[0].CsType);
var refCol = Expression.MakeMemberAccess(otmExpParm1, tbref2.Properties[tbref.RefColumns[0].CsName]);
//if (refCol.Type.IsNullableType()) refCol = Expression.Property(refCol, CommonExpression._dicNullableValueProperty.GetOrAdd(refCol.Type, ct1 => ct1.GetProperty("Value")));
subSelect.Where(Expression.Lambda<Func<TNavigate, bool>>(
Expression.Call(null, containsMethod, arrExp, refCol), otmExpParm1));
}
else
{
var sbDic = getWhereDic();
var sbWhere = new StringBuilder();
foreach (var sbd in sbDic)
sbWhere.Append(" OR ").Append(sbd.Key);
subSelect.Where(sbWhere.Remove(0, 4).ToString());
sbWhere.Clear();
sbDic.Clear();
}
subSelect.Where(oldWhere);
subList = subSelect.ToList(true);
}
if (subList.Any() == false)
{
foreach (var item in list)
setListValue(item, new List<TNavigate>());
return;
}
Dictionary<string, List<Tuple<T1, List<TNavigate>>>> dicList = new Dictionary<string, List<Tuple<T1, List<TNavigate>>>>();
foreach (var item in list)
{
if (tbref.Columns.Count == 1)
{
var dicListKey = getListValue(item, tbref.Columns[0].CsName, 0).ToString();
var dicListVal = Tuple.Create(item, new List<TNavigate>());
if (dicList.TryGetValue(dicListKey, out var items) == false)
dicList.Add(dicListKey, items = new List<Tuple<T1, List<TNavigate>>>());
items.Add(dicListVal);
}
else
{
var sb = new StringBuilder();
for (var z = 0; z < tbref.Columns.Count; z++)
{
if (z > 0) sb.Append("*$*");
sb.Append(getListValue(item, tbref.Columns[z].CsName, z));
}
var dicListKey = sb.ToString();
var dicListVal = Tuple.Create(item, new List<TNavigate>());
if (dicList.TryGetValue(dicListKey, out var items) == false)
dicList.Add(dicListKey, items = new List<Tuple<T1, List<TNavigate>>>());
items.Add(dicListVal);
sb.Clear();
}
}
var parentNavs = new List<string>();
foreach (var navProp in tbref2.Properties)
{
if (tbref2.ColumnsByCs.ContainsKey(navProp.Key)) continue;
if (tbref2.ColumnsByCsIgnore.ContainsKey(navProp.Key)) continue;
var tr2ref = tbref2.GetTableRef(navProp.Key, false);
if (tr2ref == null) continue;
if (tr2ref.RefType != TableRefType.ManyToOne) continue;
if (tr2ref.RefEntityType != tb.Type) continue;
parentNavs.Add(navProp.Key);
}
foreach (var nav in subList)
{
string key = null;
if (tbref.RefColumns.Count == 1)
{
key = _orm.GetEntityValueWithPropertyName(tbref.RefEntityType, nav, tbref.RefColumns[0].CsName).ToString();
}
else
{
var sb = new StringBuilder();
for (var z = 0; z < tbref.RefColumns.Count; z++)
{
if (z > 0) sb.Append("*$*");
sb.Append(_orm.GetEntityValueWithPropertyName(tbref.RefEntityType, nav, tbref.RefColumns[z].CsName));
}
key = sb.ToString();
sb.Clear();
}
if (dicList.TryGetValue(key, out var t1items) == false) return;
foreach (var t1item in t1items)
t1item.Item2.Add(nav);
//将子集合的,多对一,对象设置为当前对象
foreach (var parentNav in parentNavs)
foreach (var t1item in t1items)
_orm.SetEntityValueWithPropertyName(tbref.RefMiddleEntityType, nav, parentNav, t1item.Item1);
}
foreach (var t1items in dicList.Values)
foreach (var t1item in t1items)
setListValue(t1item.Item1, t1item.Item2);
dicList.Clear();
}
break;
case TableRefType.ManyToMany:
if (true)
{
List<TNavigate> subList = null;
List<object> midList = new List<object>();
var tbref2 = _commonUtils.GetTableByEntity(tbref.RefEntityType);
var tbrefMid = _commonUtils.GetTableByEntity(tbref.RefMiddleEntityType);
var sbJoin = new StringBuilder().Append($"{_commonUtils.QuoteSqlName(tbrefMid.DbName)} midtb ON ");
for (var z = 0; z < tbref.RefColumns.Count; z++)
{
if (z > 0) sbJoin.Append(" AND ");
sbJoin.Append($"midtb.{_commonUtils.QuoteSqlName(tbref.MiddleColumns[tbref.Columns.Count + z].Attribute.Name)} = a.{_commonUtils.QuoteSqlName(tbref.RefColumns[z].Attribute.Name)}");
if (_whereCascadeExpression.Any()) {
var cascade = _commonExpression.GetWhereCascadeSql(new SelectTableInfo { Alias = "midtb", AliasInit = "midtb", Table = tbrefMid, Type = SelectTableInfoType.InnerJoin }, _whereCascadeExpression);
if (string.IsNullOrEmpty(cascade) == false)
sbJoin.Append(" AND (").Append(cascade).Append(")");
}
}
subSelect.InnerJoin(sbJoin.ToString());
sbJoin.Clear();
var af = subSelect.GetAllFieldExpressionTreeLevelAll();
(string field, ReadAnonymousTypeInfo read)? otherData = null;
var sbSql = new StringBuilder();
if (_selectExpression == null)
{// return this.InternalToList<T1>(_selectExpression).Select(a => (a, ()).ToList();
var field = new StringBuilder();
var read = new ReadAnonymousTypeInfo();
read.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties;
read.Consturctor = (tbrefMid.TypeLazy ?? tbrefMid.Type).GetConstructor(new Type[0]);
read.Table = tbrefMid;
foreach (var col in tbrefMid.Columns.Values)
{
if (tbref.MiddleColumns.Where(a => a.CsName == col.CsName).Any() == false) continue;
var child = new ReadAnonymousTypeInfo
{
CsName = col.CsName,
CsType = col.CsType,
DbField = $"midtb.{_commonUtils.QuoteSqlName(col.Attribute.Name)}",
MapType = col.Attribute.MapType,
Property = tbrefMid.Properties[col.CsName]
};
read.Childs.Add(child);
field.Append(", ").Append(_commonUtils.QuoteReadColumn(child.MapType, child.DbField));
}
otherData = (field.ToString(), read);
}
Func<Dictionary<string, bool>> getWhereDic = () =>
{
var sbDic = new Dictionary<string, bool>();
for (var y = 0; y < list.Count; y++)
{
var sbWhereOne = new StringBuilder();
sbWhereOne.Append("(");
for (var z = 0; z < tbref.Columns.Count; z++)
{
if (z > 0) sbWhereOne.Append(" AND ");
sbWhereOne.Append(_commonUtils.FormatSql($" midtb.{_commonUtils.QuoteSqlName(tbref.MiddleColumns[z].Attribute.Name)}={{0}}", Utils.GetDataReaderValue(tbref.MiddleColumns[z].Attribute.MapType, getListValue1(list[y], tbref.Columns[z].CsName))));
}
sbWhereOne.Append(")");
var whereOne = sbWhereOne.ToString();
sbWhereOne.Clear();
if (sbDic.ContainsKey(whereOne) == false) sbDic.Add(whereOne, true);
}
return sbDic;
};
if (takeNumber > 0)
{
var sbDic = getWhereDic();
foreach (var sbd in sbDic)
{
subSelect._where.Clear();
subSelect.Where(sbd.Key).Where(oldWhere).Limit(takeNumber);
sbSql.Append("\r\nUNION ALL\r\nselect * from (").Append(subSelect.ToSql($"{af.Field}{otherData?.field}")).Append(") ftb");
}
sbSql.Remove(0, 13);
if (sbDic.Count == 1) sbSql.Remove(0, 15).Remove(sbSql.Length - 5, 5);
sbDic.Clear();
}
else
{
subSelect._where.Clear();
if (tbref.Columns.Count == 1)
{
subSelect.Where(_commonUtils.FormatSql($"midtb.{_commonUtils.QuoteSqlName(tbref.MiddleColumns[0].Attribute.Name)} in {{0}}", list.Select(a => Utils.GetDataReaderValue(tbref.MiddleColumns[0].Attribute.MapType, getListValue1(a, tbref.Columns[0].CsName))).Distinct()));
}
else
{
var sbDic = getWhereDic();
var sbWhere = new StringBuilder();
foreach (var sbd in sbDic)
sbWhere.Append(" OR ").Append(sbd.Key);
subSelect.Where(sbWhere.Remove(0, 4).ToString());
sbWhere.Clear();
sbDic.Clear();
}
subSelect.Where(oldWhere);
sbSql.Append(subSelect.ToSql($"{af.Field}{otherData?.field}"));
}
subList = subSelect.ToListAfPrivate(sbSql.ToString(), af, otherData == null ? null : new[] { (otherData.Value.field, otherData.Value.read, midList) });
if (subList.Any() == false)
{
foreach (var item in list)
setListValue(item, new List<TNavigate>());
return;
}
Dictionary<string, List<Tuple<T1, List<TNavigate>>>> dicList = new Dictionary<string, List<Tuple<T1, List<TNavigate>>>>();
foreach (var item in list)
{
if (tbref.Columns.Count == 1)
{
var dicListKey = getListValue1(item, tbref.Columns[0].CsName).ToString();
var dicListVal = Tuple.Create(item, new List<TNavigate>());
if (dicList.TryGetValue(dicListKey, out var items) == false)
dicList.Add(dicListKey, items = new List<Tuple<T1, List<TNavigate>>>());
items.Add(dicListVal);
}
else
{
var sb = new StringBuilder();
for (var z = 0; z < tbref.Columns.Count; z++)
{
if (z > 0) sb.Append("*$*");
sb.Append(getListValue1(item, tbref.Columns[z].CsName));
}
var dicListKey = sb.ToString();
var dicListVal = Tuple.Create(item, new List<TNavigate>());
if (dicList.TryGetValue(dicListKey, out var items) == false)
dicList.Add(dicListKey, items = new List<Tuple<T1, List<TNavigate>>>());
items.Add(dicListVal);
sb.Clear();
}
}
for (var a = 0; a < subList.Count; a++)
{
string key = null;
if (tbref.Columns.Count == 1)
key = _orm.GetEntityValueWithPropertyName(tbref.RefMiddleEntityType, midList[a], tbref.MiddleColumns[0].CsName).ToString();
else
{
var sb = new StringBuilder();
for (var z = 0; z < tbref.Columns.Count; z++)
{
if (z > 0) sb.Append("*$*");
sb.Append(_orm.GetEntityValueWithPropertyName(tbref.RefMiddleEntityType, midList[a], tbref.MiddleColumns[z].CsName));
}
key = sb.ToString();
sb.Clear();
}
if (dicList.TryGetValue(key, out var t1items) == false) return;
foreach (var t1item in t1items)
t1item.Item2.Add(subList[a]);
}
foreach (var t1items in dicList.Values)
foreach (var t1item in t1items)
setListValue(t1item.Item1, t1item.Item2);
dicList.Clear();
}
break;
}
});
return this;
}
internal void SetList(IEnumerable<T1> list)
{
foreach (var include in _includeToList) include?.Invoke(list);
_trackToList?.Invoke(list);
}
#if net40
#else
public Task<TMember> AvgAsync<TMember>(Expression<Func<T1, TMember>> column)
{
if (column == null) return Task.FromResult(default(TMember));
_tables[0].Parameter = column.Parameters[0];
return this.InternalAvgAsync<TMember>(column?.Body);
}
public Task<TMember> MaxAsync<TMember>(Expression<Func<T1, TMember>> column)
{
if (column == null) return Task.FromResult(default(TMember));
_tables[0].Parameter = column.Parameters[0];
return this.InternalMaxAsync<TMember>(column?.Body);
}
public Task<TMember> MinAsync<TMember>(Expression<Func<T1, TMember>> column)
{
if (column == null) return Task.FromResult(default(TMember));
_tables[0].Parameter = column.Parameters[0];
return this.InternalMinAsync<TMember>(column?.Body);
}
public Task<TMember> SumAsync<TMember>(Expression<Func<T1, TMember>> column)
{
if (column == null) return Task.FromResult(default(TMember));
_tables[0].Parameter = column.Parameters[0];
return this.InternalSumAsync<TMember>(column?.Body);
}
public Task<List<TReturn>> ToListAsync<TReturn>(Expression<Func<T1, TReturn>> select)
{
if (select == null) return this.InternalToListAsync<TReturn>(select?.Body);
_tables[0].Parameter = select.Parameters[0];
return this.InternalToListAsync<TReturn>(select?.Body);
}
public Task<List<TDto>> ToListAsync<TDto>() => ToListAsync(GetToListDtoSelector<TDto>());
public Task<DataTable> ToDataTableAsync<TReturn>(Expression<Func<T1, TReturn>> select)
{
if (select == null) return this.InternalToDataTableAsync(select?.Body);
_tables[0].Parameter = select.Parameters[0];
return this.InternalToDataTableAsync(select?.Body);
}
public Task<TReturn> ToAggregateAsync<TReturn>(Expression<Func<ISelectGroupingAggregate<T1>, TReturn>> select)
{
if (select == null) return Task.FromResult(default(TReturn));
_tables[0].Parameter = select.Parameters[0];
return this.InternalToAggregateAsync<TReturn>(select?.Body);
}
public Task<bool> AnyAsync(Expression<Func<T1, bool>> exp) => this.Where(exp).AnyAsync();
async public Task<TReturn> ToOneAsync<TReturn>(Expression<Func<T1, TReturn>> select) => (await this.Limit(1).ToListAsync(select)).FirstOrDefault();
async public Task<TDto> ToOneAsync<TDto>() => (await this.Limit(1).ToListAsync<TDto>()).FirstOrDefault();
public Task<TReturn> FirstAsync<TReturn>(Expression<Func<T1, TReturn>> select) => this.ToOneAsync(select);
public Task<TDto> FirstAsync<TDto>() => this.ToOneAsync<TDto>();
public override Task<List<T1>> ToListAsync(bool includeNestedMembers = false) => base.ToListAsync(_isIncluded || includeNestedMembers);
#endif
}
}