using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; namespace SqlSugar { internal class OneToManyNavgateExpression { private SqlSugarProvider context; private EntityInfo EntityInfo; private EntityInfo ProPertyEntity; private Navigate Navigat; public string ShorName; public string PropertyShortName; private string MemberName; private string MethodName; private string whereSql; public int ParameterIndex = 0; private MethodCallExpressionResolve methodCallExpressionResolve; public OneToManyNavgateExpression(SqlSugarProvider context, MethodCallExpressionResolve methodCallExpressionResolve) { this.context = context; this.methodCallExpressionResolve = methodCallExpressionResolve; } 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; MethodName = memberExp.Method.Name; if (memberExp.Method.Name.IsIn("Any","Count") && memberExp.Arguments.Count>0 && memberExp.Arguments[0] is MemberExpression ) { result = ValidateNav(result, memberExp.Arguments[0] as MemberExpression, memberExp.Arguments[0]); if (memberExp.Arguments.Count > 1) { var pars = ExpressionTool.ExpressionParameters(memberExp.Arguments.Last()); if (pars != null&& ProPertyEntity!=null&& pars.Any(z => z.Type == ProPertyEntity.Type)) { PropertyShortName = pars.First(z => z.Type == ProPertyEntity.Type).Name; } whereSql = GetWhereSql(memberExp); } } } return result; } private string GetWhereSql(MethodCallExpression memberExp) { var whereExp = memberExp.Arguments[1]; if (PropertyShortName.HasValue() && Navigat != null && Navigat.NavigatType == NavigateType.OneToMany) { InitType(whereExp); var result = this.methodCallExpressionResolve.GetNewExpressionValue(whereExp, ResolveExpressType.WhereMultiple); return result; } else if (whereExp!=null&&whereExp.Type == typeof(List)) { var value = ExpressionTool.GetExpressionValue(whereExp) as List; //this.context.Utilities.Context.Queryable().Where(value).ToList(); if (value.HasValue()) { var sqlbuilder = this.context.Queryable().SqlBuilder; var sqlObj = sqlbuilder.ConditionalModelToSql(value, 0); var sql = sqlObj.Key; var count = methodCallExpressionResolve?.Context?.SugarContext?.QueryBuilder?.Parameters?.Count??0; UtilMethods.RepairReplicationParameters(ref sql, sqlObj.Value,0,"_"+ count+"_"); methodCallExpressionResolve.Context.Parameters.AddRange(sqlObj.Value); return sql; } else { return " 1=1 "; } } else { InitType(whereExp); var result = this.methodCallExpressionResolve.GetNewExpressionValue(whereExp); return result; } } private void InitType(Expression whereExp) { if (whereExp is LambdaExpression) { var parameters = (whereExp as LambdaExpression).Parameters; if (parameters != null && parameters.Count > 0) { foreach (var item in parameters) { this.context.InitMappingInfo(item.Type); } } } } private bool ValidateNav(bool result, MemberExpression memberExp, Expression childExpression) { if (childExpression != null && childExpression is MemberExpression) { var child2Expression = (childExpression as MemberExpression).Expression; if (child2Expression.Type.IsClass() && child2Expression is ParameterExpression) { var rootType = child2Expression.Type; var rootEntity = this.context.EntityMaintenance.GetEntityInfo(rootType); var type= childExpression.Type.GetGenericArguments()[0]; var entity = this.context.EntityMaintenance.GetEntityInfo(type); if (rootEntity.Columns.Any(x => x.PropertyName == (childExpression as MemberExpression).Member.Name && x.Navigat != null)) { EntityInfo = rootEntity; ShorName = child2Expression.ToString(); MemberName = memberExp.Member.Name; ProPertyEntity = entity; Navigat = rootEntity.Columns.FirstOrDefault(x => x.PropertyName == (childExpression as MemberExpression).Member.Name).Navigat; result = true; } } } return result; } internal MapperSql GetSql() { if (Navigat.NavigatType == NavigateType.OneToMany) { return GetOneToManySql(); } else if (Navigat.NavigatType == NavigateType.Dynamic) { return GetDynamicSql(); } else { return GetManyToManySql(); } } private MapperSql GetDynamicSql() { if (Navigat.Name == null) { Check.ExceptionEasy( true, " NavigateType.Dynamic User-defined navigation objects need to be configured with json to be used in expressions . " + this.ProPertyEntity.Type.Name, " NavigateType.Dynamic 自定义导航对象需要配置json才能在表达式中使用。 " + this.ProPertyEntity.Type.Name); } MapperSql mapper = new MapperSql(); var queryable = this.context.Queryable(); //selectName = queryable.QueryBuilder.Builder.GetTranslationColumnName(selectName); if (PropertyShortName.HasValue()) { queryable.QueryBuilder.TableShortName = PropertyShortName; } queryable.QueryBuilder.LambdaExpressions.ParameterIndex = 500; var isClearFilter = false; Type[] clearTypes = null; if (this.methodCallExpressionResolve?.Context?.SugarContext?.QueryBuilder != null) { queryable.QueryBuilder.LambdaExpressions.ParameterIndex = 500 + this.methodCallExpressionResolve.Context.SugarContext.QueryBuilder.LambdaExpressions.ParameterIndex; this.methodCallExpressionResolve.Context.SugarContext.QueryBuilder.LambdaExpressions.ParameterIndex++; isClearFilter = this.methodCallExpressionResolve.Context.SugarContext.QueryBuilder.IsDisabledGobalFilter; clearTypes = this.methodCallExpressionResolve.Context.SugarContext.QueryBuilder.RemoveFilters; } queryable .AS(this.ProPertyEntity.DbTableName) .ClearFilter(clearTypes) .Filter(isClearFilter ? null : this.ProPertyEntity.Type) .WhereIF(!string.IsNullOrEmpty(whereSql), whereSql); var json = Newtonsoft.Json.Linq.JArray.Parse(Navigat.Name); foreach (var item in json) { string m = item["m"] + ""; string c = item["c"] + ""; var leftName = this.EntityInfo.Columns.First(it => it.PropertyName == m).DbColumnName; var rightName = this.ProPertyEntity.Columns.First(it => it.PropertyName == c).DbColumnName; queryable.Where($" {queryable.SqlBuilder.GetTranslationColumnName(ShorName)}.{queryable.SqlBuilder.GetTranslationColumnName(leftName)}={queryable.SqlBuilder.GetTranslationColumnName(rightName)} "); } var sqlObj = queryable.ToSql(); // .Where($" {name}={queryable.QueryBuilder.Builder.GetTranslationColumnName(ShorName)}.{pk} ").Select(MethodName == "Any" ? "1" : " COUNT(1) ").ToSql(); if (sqlObj.Value?.Any() == true) { foreach (var item in sqlObj.Value) { if (!this.methodCallExpressionResolve.Context.Parameters.Any(it => it.ParameterName == item.ParameterName)) { this.methodCallExpressionResolve.Context.Parameters.Add(item); } } } mapper.Sql = sqlObj.Key; mapper.Sql = $" ({mapper.Sql}) "; mapper.Sql = GetMethodSql(mapper.Sql); return mapper; } private MapperSql GetManyToManySql() { var bPk = this.ProPertyEntity.Columns.FirstOrDefault(it => it.IsPrimarykey == true)?.DbColumnName; var aPk = this.EntityInfo.Columns.FirstOrDefault(it => it.IsPrimarykey == true)?.DbColumnName; if (Navigat.BClassId.HasValue()) { bPk= this.ProPertyEntity.Columns.FirstOrDefault(it => it.PropertyName == Navigat.BClassId)?.DbColumnName; } if (Navigat.AClassId.HasValue()) { aPk = this.EntityInfo.Columns.FirstOrDefault(it => it.PropertyName == Navigat.AClassId)?.DbColumnName; } Check.ExceptionEasy(aPk.IsNullOrEmpty(), $"{this.EntityInfo.EntityName}need primary key", $"{this.EntityInfo.EntityName}需要主键"); Check.ExceptionEasy(bPk.IsNullOrEmpty(), $"{this.ProPertyEntity.EntityName}need primary key", $"{this.ProPertyEntity.EntityName}需要主键"); MapperSql mapper = new MapperSql(); var queryable = this.context.Queryable(); bPk = queryable.QueryBuilder.Builder.GetTranslationColumnName(bPk); aPk = queryable.QueryBuilder.Builder.GetTranslationColumnName(aPk); var mappingType = Navigat.MappingType; Check.ExceptionEasy(mappingType == null, "ManyToMany misconfiguration", "多对多配置错误"); var mappingEntity = this.context.EntityMaintenance.GetEntityInfo(mappingType); var mappingTableName=queryable.QueryBuilder.Builder.GetTranslationTableName(mappingEntity.DbTableName); var mappingA = mappingEntity.Columns.First(it => it.PropertyName == Navigat.MappingAId).DbColumnName; var mappingB = mappingEntity.Columns.First(it => it.PropertyName == Navigat.MappingBId).DbColumnName; mappingA = queryable.QueryBuilder.Builder.GetTranslationColumnName(mappingA); mappingB = queryable.QueryBuilder.Builder.GetTranslationColumnName(mappingB); var bTableName = queryable.QueryBuilder.Builder.GetTranslationTableName(this.ProPertyEntity.DbTableName); this.context.InitMappingInfo(mappingType); var queryBuilerAB=this.context.Queryable().QueryBuilder; queryBuilerAB.LambdaExpressions.ParameterIndex = 100+this.ParameterIndex; var filters= queryBuilerAB.GetFilters(mappingType); if (filters.HasValue()&& this.methodCallExpressionResolve?.Context?.SugarContext?.QueryBuilder?.IsDisabledGobalFilter!=true) { aPk += " AND " + filters; if (queryBuilerAB.Parameters != null) { this.methodCallExpressionResolve.Context.Parameters.AddRange(queryBuilerAB.Parameters); } } mapper.Sql = $" (select {(MethodName == "Any" ? "1":" COUNT(1) ")} from {bTableName} {this.ProPertyEntity.DbTableName}_1 where {this.ProPertyEntity.DbTableName}_1.{bPk} in (select {mappingB} from {mappingTableName} where {mappingA} = {ShorName}.{aPk} ) )"; if (this.whereSql.HasValue()) { mapper.Sql = mapper.Sql.TrimEnd(')'); if (this.whereSql.Contains($" {PropertyShortName}.")) { this.whereSql = this.whereSql.Replace($" {PropertyShortName}.", $" {this.ProPertyEntity.DbTableName}_1."); } else if (this.whereSql.Contains($" {queryable.QueryBuilder.Builder.GetTranslationColumnName(PropertyShortName)}.")) { this.whereSql = this.whereSql.Replace($" {queryable.QueryBuilder.Builder.GetTranslationColumnName(PropertyShortName)}.", $" {this.ProPertyEntity.DbTableName}_1."); } else if (this.whereSql.Contains($"({queryable.QueryBuilder.Builder.GetTranslationColumnName(PropertyShortName)}.")) { this.whereSql = this.whereSql.Replace($"({queryable.QueryBuilder.Builder.GetTranslationColumnName(PropertyShortName)}.", $"({this.ProPertyEntity.DbTableName}_1."); } mapper.Sql = mapper.Sql + " AND " + this.whereSql+")"; } if (MethodName == "Any") { mapper.Sql = $" {mapper.Sql} "; } else { mapper.Sql = $" ({mapper.Sql}) "; } mapper.Sql = GetMethodSql(mapper.Sql); return mapper; } private MapperSql GetOneToManySql() { var pkColumn = this.EntityInfo.Columns.FirstOrDefault(it => it.IsPrimarykey == true); if (Navigat.Name2.HasValue()) { pkColumn = this.EntityInfo.Columns.FirstOrDefault(it => it.PropertyName== Navigat.Name2); } Check.ExceptionEasy(pkColumn == null, $"{this.EntityInfo.EntityName} need primary key ", $"导航属性 {this.EntityInfo.EntityName}需要主键"); var pk = pkColumn.DbColumnName; var name = this.ProPertyEntity.Columns.First(it => it.PropertyName == Navigat.Name).DbColumnName; //var selectName = this.ProPertyEntity.Columns.First(it => it.PropertyName == MemberName).DbColumnName; MapperSql mapper = new MapperSql(); var queryable = this.context.Queryable(); pk = queryable.QueryBuilder.Builder.GetTranslationColumnName(pk); name = queryable.QueryBuilder.Builder.GetTranslationColumnName(name); //selectName = queryable.QueryBuilder.Builder.GetTranslationColumnName(selectName); if (PropertyShortName.HasValue()) { queryable.QueryBuilder.TableShortName = PropertyShortName; } queryable.QueryBuilder.LambdaExpressions.ParameterIndex = 500; var isClearFilter = false; Type[] clearTypes = null; if (this.methodCallExpressionResolve?.Context?.SugarContext?.QueryBuilder != null) { queryable.QueryBuilder.LambdaExpressions.ParameterIndex=500+ this.methodCallExpressionResolve.Context.SugarContext.QueryBuilder.LambdaExpressions.ParameterIndex; this.methodCallExpressionResolve.Context.SugarContext.QueryBuilder.LambdaExpressions.ParameterIndex++; isClearFilter=this.methodCallExpressionResolve.Context.SugarContext.QueryBuilder.IsDisabledGobalFilter; clearTypes = this.methodCallExpressionResolve.Context.SugarContext.QueryBuilder.RemoveFilters; } var sqlObj = queryable .AS(this.ProPertyEntity.DbTableName) .ClearFilter(clearTypes) .Filter(isClearFilter?null:this.ProPertyEntity.Type) .WhereIF(!string.IsNullOrEmpty(whereSql), whereSql) .Where($" {name}={queryable.QueryBuilder.Builder.GetTranslationColumnName( ShorName)}.{pk} ").Select(MethodName == "Any" ? "1" : " COUNT(1) ").ToSql(); if (sqlObj.Value?.Any() == true) { foreach (var item in sqlObj.Value) { if (!this.methodCallExpressionResolve.Context.Parameters.Any(it => it.ParameterName == item.ParameterName)) { this.methodCallExpressionResolve.Context.Parameters.Add(item); } } } mapper.Sql = sqlObj.Key; mapper.Sql = $" ({mapper.Sql}) "; mapper.Sql = GetMethodSql(mapper.Sql); return mapper; } private string GetMethodSql(string sql) { if (MethodName == "Any") { return $" ( EXISTS {sql} ) "; } return sql; } } }