using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace SqlSugar { internal class OneToManyNavgateExpressionN { #region Constructor public SqlSugarProvider context; public string shorName; public EntityInfo entityInfo; public List items; public string whereSql; public MethodCallExpressionResolve methodCallExpressionResolve; public OneToManyNavgateExpressionN(SqlSugarProvider context, MethodCallExpressionResolve methodCallExpressionResolve) { this.context = context; this.methodCallExpressionResolve= methodCallExpressionResolve; } #endregion internal bool IsNavgate(Expression expression) { var result = false; var exp = expression; if (exp is UnaryExpression) { exp = (exp as UnaryExpression).Operand; } if (exp is MethodCallExpression) { var memberExp=exp as MethodCallExpression; if (memberExp.Method.Name.IsIn("Any","Count") && memberExp.Arguments.Count>0 && memberExp.Arguments[0] is MemberExpression ) { result = ValiteOneManyCall(result, memberExp, memberExp.Arguments[0] as MemberExpression, memberExp.Arguments[0]); if (memberExp.Arguments.Count > 1) { whereSql = GetWhereSql(memberExp); } } } return result; } private bool ValiteOneManyCall(bool result,MethodCallExpression callExpression, MemberExpression memberExp, Expression childExpression) { if (childExpression != null && childExpression is MemberExpression) { var oldChildExpression = childExpression; var child2Expression = (childExpression as MemberExpression).Expression; if (child2Expression == null || (child2Expression is ConstantExpression)) { return false; } items = new List(); var childType = oldChildExpression.Type; if (!childType.FullName.IsCollectionsList()) { return false; } childType = childType.GetGenericArguments()[0]; items.Add(new ExpressionItems() { Type = 3, Expression = callExpression, ParentEntityInfo = this.context.EntityMaintenance.GetEntityInfo(childType) }); items.Add(new ExpressionItems() { Type = 2, Expression = oldChildExpression, ThisEntityInfo = this.context.EntityMaintenance.GetEntityInfo(childType), ParentEntityInfo = this.context.EntityMaintenance.GetEntityInfo(child2Expression.Type) }); if (items.Any(it => it.Type == 2 && it.Nav == null)) { return false; } while (child2Expression != null) { if (IsClass(child2Expression)) { items.Add(new ExpressionItems() { Type = 2, Expression = child2Expression, ThisEntityInfo = this.context.EntityMaintenance.GetEntityInfo(child2Expression.Type), ParentEntityInfo = this.context.EntityMaintenance.GetEntityInfo(GetMemberExpression(child2Expression).Type) }); child2Expression = GetMemberExpression(child2Expression); } else if (IsParameter(child2Expression)) { shorName = child2Expression.ToString(); entityInfo = this.context.EntityMaintenance.GetEntityInfo(child2Expression.Type); break; } else { break; } } if (!items.Any(it => it.Type == 2 && it.Nav == null)) { return true; } } return result; } public object GetSql() { MapperSql MapperSql = new MapperSql(); var memberInfo = this.items.Where(it => it.Type == 3).First(); var subInfos = this.items.Where(it => it.Type == 2).Reverse().ToList(); var formInfo = subInfos.First(); var joinInfos = subInfos.Skip(1).ToList(); var i = 0; var masterShortName = formInfo.ThisEntityInfo.DbTableName + i; var queryable = this.context.Queryable(masterShortName).AS(formInfo.ThisEntityInfo.DbTableName); i++; var lastShortName = ""; var index = 0; foreach (var item in joinInfos) { if (item.Nav.NavigatType == NavigateType.OneToMany) { lastShortName = OneToMany(ref formInfo, ref i, queryable, ref index, item); } else { lastShortName = ManyToMany(ref formInfo, ref i, queryable, ref index, item); } } var isAny = (memberInfo.Expression as MethodCallExpression).Method.Name == "Any"; queryable.Select(isAny ? "1" : " COUNT(1) "); var last = subInfos.First(); var FirstPkColumn = last.ThisEntityInfo.Columns.FirstOrDefault(it => it.IsPrimarykey); FirstPkColumn = GetFirstPkColumn(last, FirstPkColumn); Check.ExceptionEasy(FirstPkColumn == null, $"{ last.ThisEntityInfo.EntityName} need PrimayKey", $"使用导航属性{ last.ThisEntityInfo.EntityName} 缺少主键"); var PkColumn = last.ParentEntityInfo.Columns.FirstOrDefault(it => it.PropertyName == last.Nav.Name); Check.ExceptionEasy(PkColumn == null, $"{ last.ParentEntityInfo.EntityName} no found {last.Nav.Name}", $"{ last.ParentEntityInfo.EntityName} 不存在 {last.Nav.Name}"); queryable.Where($" {this.shorName}.{ queryable.SqlBuilder.GetTranslationColumnName(PkColumn.DbColumnName)} = {masterShortName}.{queryable.SqlBuilder.GetTranslationColumnName(FirstPkColumn.DbColumnName)} "); queryable.WhereIF(this.whereSql.HasValue(), GetWhereSql1(this.whereSql,lastShortName, joinInfos, queryable.SqlBuilder)); MapperSql.Sql = $"( {queryable.ToSql().Key} ) "; if (isAny) { MapperSql.Sql = $" EXISTS( {MapperSql.Sql}) "; } return MapperSql; } private static EntityColumnInfo GetFirstPkColumn(ExpressionItems last, EntityColumnInfo FirstPkColumn) { if (last.Nav.NavigatType == NavigateType.OneToOne && last.Nav.Name2.HasValue()) { var name2 = last.ThisEntityInfo.Columns.FirstOrDefault(it => it.PropertyName == last.Nav.Name2); if (name2 != null) { FirstPkColumn = name2; } } return FirstPkColumn; } private static string OneToMany(ref ExpressionItems formInfo, ref int i, ISugarQueryable queryable, ref int index, ExpressionItems item) { string lastShortName; var shortName = item.ThisEntityInfo.DbTableName + i; EntityColumnInfo pkColumn; EntityColumnInfo navColum; if (index == 0) { pkColumn = item.ThisEntityInfo.Columns.FirstOrDefault(it => it.PropertyName == item.Nav.Name); navColum = item.ParentEntityInfo.Columns.FirstOrDefault(it => it.IsPrimarykey); } else { pkColumn = item.ThisEntityInfo.Columns.FirstOrDefault(it => it.IsPrimarykey); navColum = item.ParentEntityInfo.Columns.FirstOrDefault(it => it.PropertyName == item.Nav.Name); } Check.ExceptionEasy(pkColumn == null, $"{item.ThisEntityInfo.EntityName} need PrimayKey", $"使用导航属性{item.ThisEntityInfo.EntityName} 缺少主键"); var on = $" {shortName}.{queryable.SqlBuilder.GetTranslationColumnName(pkColumn.DbColumnName)}={formInfo.ThisEntityInfo.DbTableName + (i - 1)}.{queryable.SqlBuilder.GetTranslationColumnName(navColum.DbColumnName)}"; queryable.AddJoinInfo(item.ThisEntityInfo.DbTableName, shortName, on, JoinType.Inner); ++i; index++; lastShortName = shortName; formInfo = item; return lastShortName; } private string ManyToMany(ref ExpressionItems formInfo, ref int i, ISugarQueryable queryable, ref int index, ExpressionItems item) { string lastShortName; var bshortName = item.ThisEntityInfo.DbTableName + i; EntityColumnInfo AidColumn; EntityColumnInfo BidColumn; BidColumn = item.ThisEntityInfo.Columns.FirstOrDefault(it => it.IsPrimarykey); AidColumn = item.ParentEntityInfo.Columns.FirstOrDefault(it => it.IsPrimarykey); var abEntity =this.context.EntityMaintenance.GetEntityInfo(item.Nav.MappingType); var Ab_Aid = abEntity.Columns.FirstOrDefault(it => item.Nav.MappingAId == it.PropertyName); var Ab_Bid = abEntity.Columns.FirstOrDefault(it => item.Nav.MappingBId == it.PropertyName); Check.ExceptionEasy(AidColumn == null, $" {AidColumn.EntityName} need primary key ", $"{AidColumn.EntityName}需要主键"); Check.ExceptionEasy(AidColumn == null, $" {BidColumn.EntityName} need primary key ", $"{BidColumn.EntityName}需要主键"); var abShort = abEntity.EntityName + "_1"; var abOn = $" {abShort}.{queryable.SqlBuilder.GetTranslationColumnName(Ab_Aid.DbColumnName)}={formInfo.ThisEntityInfo.DbTableName + (i - 1)}.{queryable.SqlBuilder.GetTranslationColumnName(AidColumn.DbColumnName)}"; queryable.AddJoinInfo(abEntity.DbTableName, abShort, abOn, JoinType.Inner); var On = $" {bshortName}.{queryable.SqlBuilder.GetTranslationColumnName(BidColumn.DbColumnName)}={abShort}.{queryable.SqlBuilder.GetTranslationColumnName(Ab_Bid.DbColumnName)}"; queryable.AddJoinInfo(BidColumn.DbTableName, bshortName, On, JoinType.Inner); ++i; index++; lastShortName = bshortName; formInfo = item; return lastShortName; } #region Helper private string GetWhereSql1(string wheresql,string lastShortName, List joinInfos,ISqlBuilder sqlBuilder) { var sql = wheresql; if (sql == null) return sql; joinInfos.Last().ThisEntityInfo.Columns.ForEach(it => { if (it.DbColumnName != null) { if (this.whereSql.Contains("." + sqlBuilder.GetTranslationColumnName(it.DbColumnName))) { var regex = @"\w+\." + sqlBuilder.GetTranslationColumnName(it.DbColumnName) .Replace(sqlBuilder.SqlTranslationLeft, "\\" + sqlBuilder.SqlTranslationLeft) .Replace(sqlBuilder.SqlTranslationRight, "\\" + sqlBuilder.SqlTranslationRight) .Replace("\\\\","\\"); this.whereSql =Regex.Replace(this.whereSql, regex, lastShortName + "." + sqlBuilder.GetTranslationColumnName(it.DbColumnName)); } else { this.whereSql = this.whereSql.Replace(sqlBuilder.GetTranslationColumnName(it.DbColumnName), lastShortName + "." + sqlBuilder.GetTranslationColumnName(it.DbColumnName)); } } }); return this.whereSql; } private string GetWhereSql(MethodCallExpression memberExp) { var whereExp = memberExp.Arguments[1]; var result = this.methodCallExpressionResolve.GetNewExpressionValue(whereExp); return result; } private static bool IsParameter(Expression child2Expression) { return child2Expression.Type.IsClass() && child2Expression is ParameterExpression; } private static Expression GetMemberExpression(Expression child2Expression) { return (child2Expression as MemberExpression).Expression; } private static bool IsClass(Expression child2Expression) { return child2Expression.Type.IsClass() && child2Expression is MemberExpression; } #endregion } }