diff --git a/Src/Asp.Net/SqlServerTest/UnitTest/Main.cs b/Src/Asp.Net/SqlServerTest/UnitTest/Main.cs index 1c0838064..441201734 100644 --- a/Src/Asp.Net/SqlServerTest/UnitTest/Main.cs +++ b/Src/Asp.Net/SqlServerTest/UnitTest/Main.cs @@ -38,6 +38,7 @@ namespace OrmTest Json(); Ado(); Queryable(); + Queryable2(); QueryableAsync(); //Thread(); //Thread2(); diff --git a/Src/Asp.Net/SqlServerTest/UnitTest/UQueryable2.cs b/Src/Asp.Net/SqlServerTest/UnitTest/UQueryable2.cs index 983fd7682..36516f591 100644 --- a/Src/Asp.Net/SqlServerTest/UnitTest/UQueryable2.cs +++ b/Src/Asp.Net/SqlServerTest/UnitTest/UQueryable2.cs @@ -4,9 +4,22 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace OrmTest.UnitTest +namespace OrmTest { public partial class NewUnitTest { + public static void Queryable2() + { + var list4 = Db.Queryable() + .Mapper(it => it.A, it => it.AId) + .Mapper(it => it.B, it => it.BId) + .Where(it=>it.A.Name=="A") + .Where(it=>it.B.Id==1) + .Select(it=>new { + id=it.B.Id + }) + .ToList(); + + } } } diff --git a/Src/Asp.Net/SqlSugar/Abstract/QueryableProvider/QueryableProvider.cs b/Src/Asp.Net/SqlSugar/Abstract/QueryableProvider/QueryableProvider.cs index 110d88b5a..68436e235 100644 --- a/Src/Asp.Net/SqlSugar/Abstract/QueryableProvider/QueryableProvider.cs +++ b/Src/Asp.Net/SqlSugar/Abstract/QueryableProvider/QueryableProvider.cs @@ -128,6 +128,11 @@ namespace SqlSugar } public virtual ISugarQueryable Mapper(Expression> mapperObject, Expression> mapperField) { + if (CallContext.MapperExpression.Value == null) + { + CallContext.MapperExpression.Value = new List(); + } + CallContext.MapperExpression.Value.Add(new MapperExpression() { QueryBuilder = this.QueryBuilder, Type=MapperExpressionType.oneToOne, FillExpression=mapperObject, MappingField1Expression= mapperField,Context=this.Context }); return _Mapper(mapperObject, mapperField); } diff --git a/Src/Asp.Net/SqlSugar/ExpressionsToSql/Common/ExpressionTool.cs b/Src/Asp.Net/SqlSugar/ExpressionsToSql/Common/ExpressionTool.cs index da59d0284..df7cc9bdd 100644 --- a/Src/Asp.Net/SqlSugar/ExpressionsToSql/Common/ExpressionTool.cs +++ b/Src/Asp.Net/SqlSugar/ExpressionsToSql/Common/ExpressionTool.cs @@ -251,13 +251,24 @@ namespace SqlSugar public static object DynamicInvoke(Expression expression, MemberExpression memberExpression = null) { - object value = Expression.Lambda(expression).Compile().DynamicInvoke(); - if (value != null && value.GetType().IsClass() && value.GetType() != UtilConstants.StringType && memberExpression != null) + try { - value = Expression.Lambda(memberExpression).Compile().DynamicInvoke(); - } + object value = Expression.Lambda(expression).Compile().DynamicInvoke(); + if (value != null && value.GetType().IsClass() && value.GetType() != UtilConstants.StringType && memberExpression != null) + { + value = Expression.Lambda(memberExpression).Compile().DynamicInvoke(); + } - return value; + return value; + } + catch (InvalidOperationException ex) + { + return new MapperExpressionResolve(expression,ex).GetSql(); ; + } + catch (Exception ex) + { + throw new Exception("No support "+expression.ToString()+" "+ex.Message); + } } public static Type GetPropertyOrFieldType(MemberInfo propertyOrField) diff --git a/Src/Asp.Net/SqlSugar/ExpressionsToSql/Common/MapperExpression.cs b/Src/Asp.Net/SqlSugar/ExpressionsToSql/Common/MapperExpression.cs new file mode 100644 index 000000000..0b64570fd --- /dev/null +++ b/Src/Asp.Net/SqlSugar/ExpressionsToSql/Common/MapperExpression.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; + +namespace SqlSugar +{ + public class MapperExpression + { + public MapperExpressionType Type { get; set; } + public Expression FillExpression { get; set; } + public Expression MappingField1Expression { get; set; } + public Expression MappingField2Expression { get; set; } + public SqlSugarProvider Context { get; set; } + public QueryBuilder QueryBuilder { get; set; } + } + + public enum MapperExpressionType + { + oneToOne=1, + oneToN=2 + } +} diff --git a/Src/Asp.Net/SqlSugar/ExpressionsToSql/ResolveItems/BaseResolve.cs b/Src/Asp.Net/SqlSugar/ExpressionsToSql/ResolveItems/BaseResolve.cs index 856cae437..3cecb1a37 100644 --- a/Src/Asp.Net/SqlSugar/ExpressionsToSql/ResolveItems/BaseResolve.cs +++ b/Src/Asp.Net/SqlSugar/ExpressionsToSql/ResolveItems/BaseResolve.cs @@ -133,7 +133,7 @@ namespace SqlSugar if (parameter.BaseExpression is BinaryExpression || parameter.BaseExpression == null) { var oppoSiteExpression = isLeft == true ? parameter.BaseParameter.RightExpression : parameter.BaseParameter.LeftExpression; - if (parameter.CurrentExpression is MethodCallExpression||parameter.CurrentExpression is ConditionalExpression||parameter.CurrentExpression.NodeType==ExpressionType.Coalesce) + if (parameter.CurrentExpression is MethodCallExpression || parameter.CurrentExpression is ConditionalExpression || parameter.CurrentExpression.NodeType == ExpressionType.Coalesce) { var appendValue = value; if (this.Context.Result.Contains(ExpressionConst.FormatSymbol)) @@ -174,7 +174,8 @@ namespace SqlSugar this.Context.Result.Append(appendValue); } } - else if ((oppoSiteExpression is UnaryExpression && (oppoSiteExpression as UnaryExpression).Operand is MemberExpression)) { + else if ((oppoSiteExpression is UnaryExpression && (oppoSiteExpression as UnaryExpression).Operand is MemberExpression)) + { string appendValue = Context.SqlParameterKeyWord + ((MemberExpression)(oppoSiteExpression as UnaryExpression).Operand).Member.Name + Context.ParameterIndex; @@ -201,6 +202,22 @@ namespace SqlSugar this.Context.Result.Append(appendValue); } } + else if (value is MapperSql) + { + var sql = ((MapperSql)value).Sql; + if (isLeft == true) + { + sql += ExpressionConst.ExpressionReplace + parameter.BaseParameter.Index; + } + if (this.Context.Result.Contains(ExpressionConst.FormatSymbol)) + { + this.Context.Result.Replace(ExpressionConst.FormatSymbol, sql); + } + else + { + this.Context.Result.Append(sql); + } + } else { var appendValue = this.Context.SqlParameterKeyWord + ExpressionConst.Const + Context.ParameterIndex; diff --git a/Src/Asp.Net/SqlSugar/ExpressionsToSql/ResolveItems/MapperExpressionResolve.cs b/Src/Asp.Net/SqlSugar/ExpressionsToSql/ResolveItems/MapperExpressionResolve.cs new file mode 100644 index 000000000..3437c5254 --- /dev/null +++ b/Src/Asp.Net/SqlSugar/ExpressionsToSql/ResolveItems/MapperExpressionResolve.cs @@ -0,0 +1,219 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace SqlSugar +{ + public class MapperExpressionResolve + { + private Expression expression; + private List mappers; + private InvalidOperationException ex; + private SqlSugarProvider context; + private QueryBuilder querybuiler; + private string sql; + public MapperExpressionResolve(Expression expression, InvalidOperationException ex) + { + this.expression = expression; + this.ex = ex; + this.mappers = CallContext.MapperExpression.Value; + Error01(); + var isMember = expression is MemberExpression; + if (isMember) + { + ResolveMember(); + } + else + { + ResolveList(); + } + } + + private void ResolveList() + { + throw new NotImplementedException(); + } + + private void ResolveMember() + { + var exp = expression as MemberExpression; + ThrowTrue(exp.Expression == null); + var childExpression = exp.Expression; + MapperExpression mapper = GetMapper(exp); + var fillInfo=GetFillInfo(childExpression, mapper); + var mappingFild1Info = GetMappingFild1Info(childExpression, mapper); + var mappingFild1Info2 = GetMappingFild2Info(childExpression, mapper); + var SelectInfo = GetSelectInfo(expression); + var entity = this.context.EntityMaintenance.GetEntityInfo(childExpression.Type); + + var isExMapper = mappingFild1Info2!=null; + var isFillFild1SameType = fillInfo.Type == mappingFild1Info.Type; + var isSameProperty = false; + + if (isExMapper) + { + ExtMapper(); + } + else if (isSameProperty) + { + + } + else if (isFillFild1SameType) + { + oneToMany(); + } + else + { + oneToOne(fillInfo, mappingFild1Info, mappingFild1Info2,SelectInfo); + } + } + + + private void oneToOne(MapperExpressionInfo fillInfo, MapperExpressionInfo mappingFild1Info, MapperExpressionInfo mappingFild1Info2, MapperExpressionInfo selectInfo) + { + var pkColumn = selectInfo.EntityInfo.Columns.Where(it => it.IsPrimarykey == true).FirstOrDefault(); + if (pkColumn == null) + { + pkColumn = selectInfo.EntityInfo.Columns.First(); + } + this.sql = this.context.Queryable() + .AS(fillInfo.EntityInfo.DbTableName) + .Where(string.Format(" {0}={1} ", pkColumn.DbColumnName, mappingFild1Info.FieldString)) + .Select(selectInfo.FieldName).ToSql().Key; + } + + private void oneToMany() + { + throw new NotImplementedException(); + } + + private MapperExpressionInfo GetSelectInfo(Expression expression) + { + + var field = expression; + if (field is UnaryExpression) + { + field = (field as UnaryExpression).Operand; + } + var type = ((field as MemberExpression).Expression).Type; + this.context.InitMappingInfo(type); + var name = (field as MemberExpression).Member.Name; + var entity = this.context.EntityMaintenance.GetEntityInfo(type); + var fieldName = entity.Columns.First(it => it.PropertyName == name).DbColumnName; + return new MapperExpressionInfo() + { + Type = type, + FieldName = fieldName, + EntityInfo= entity + }; + } + + private MapperExpressionInfo GetMappingFild2Info(Expression childExpression, MapperExpression mapper) + { + if (mapper.MappingField2Expression == null) + return null; + var exp = mapper.MappingField2Expression; + var field = (exp as LambdaExpression).Body; + if (field is UnaryExpression) + { + field = (field as UnaryExpression).Operand; + } + var type = ((field as MemberExpression).Expression).Type; + this.context.InitMappingInfo(type); + var name = (field as MemberExpression).Member.Name; + var entity = this.context.EntityMaintenance.GetEntityInfo(type); + var fieldName = entity.Columns.First(it => it.PropertyName == name).DbColumnName; + return new MapperExpressionInfo() + { + Type = type, + FieldName = fieldName + }; + } + + private MapperExpressionInfo GetMappingFild1Info(Expression childExpression, MapperExpression mapper) + { + var exp = mapper.MappingField1Expression; + var field = (exp as LambdaExpression).Body; + if (field is UnaryExpression) + { + field = (field as UnaryExpression).Operand; + } + var type = ((field as MemberExpression).Expression).Type; + this.context.InitMappingInfo(type); + var name =(field as MemberExpression).Member.Name; + var entity = this.context.EntityMaintenance.GetEntityInfo(type); + var fieldName=entity.Columns.First(it => it.PropertyName == name).DbColumnName; + var array = (field as MemberExpression).ToString().Split('.').ToList(); + array[array.Count()-1] = fieldName; + var filedString = string.Join(".", array); + return new MapperExpressionInfo() + { + Type=type, + FieldName = fieldName, + FieldString= filedString, + EntityInfo= entity + }; + } + + private MapperExpressionInfo GetFillInfo(Expression childExpression, MapperExpression mapper) + { + this.querybuiler = mapper.QueryBuilder; + this.context = mapper.Context; + if (this.querybuiler.TableShortName.IsNullOrEmpty()) + { + this.querybuiler.TableShortName = (childExpression as MemberExpression).Expression.ToString(); + } + this.context.InitMappingInfo(childExpression.Type); + return new MapperExpressionInfo() { + EntityInfo=this.context.EntityMaintenance.GetEntityInfo(childExpression.Type) + }; + } + + private MapperExpression GetMapper(MemberExpression exp) + { + var mapper= mappers.Where(it => it.Type == MapperExpressionType.oneToOne) + .Reverse() + .Where(it => (it.FillExpression as LambdaExpression).Body.ToString() == exp.Expression.ToString()).FirstOrDefault(); + ThrowTrue(mapper == null); + return mapper; + } + + public string GetMemberName(MemberExpression memberExpression) + { + return ""; + } + + private void ExtMapper() + { + throw new NotImplementedException(); + } + + public MapperSql GetSql() + { + return new MapperSql() { Sql = " (" + this.sql + ") " }; + } + + void Error01() + { + Check.Exception(mappers == null, ErrorMessage.GetThrowMessage(expression.ToString() + "no support", "当前表达式" + expression.ToString() + "必须在Mapper之后使用")); + } + void ThrowTrue(bool isError) + { + Check.Exception(isError, ErrorMessage.GetThrowMessage(expression.ToString() + "no support", "不支持表达式" + expression.ToString())); + } + } + + public class MapperSql + { + public string Sql { get; set; } + } + + public class MapperExpressionInfo + { + public Type Type { get; set; } + public EntityInfo EntityInfo { get; set; } + public string FieldName { get; set; } + public string FieldString { get; set; } + } +} \ No newline at end of file diff --git a/Src/Asp.Net/SqlSugar/SqlSugar.csproj b/Src/Asp.Net/SqlSugar/SqlSugar.csproj index fcfefc373..9a718a07b 100644 --- a/Src/Asp.Net/SqlSugar/SqlSugar.csproj +++ b/Src/Asp.Net/SqlSugar/SqlSugar.csproj @@ -90,6 +90,8 @@ + + diff --git a/Src/Asp.Net/SqlSugar/Utilities/CallContext.cs b/Src/Asp.Net/SqlSugar/Utilities/CallContext.cs index 8cfb2d234..bd86d9958 100644 --- a/Src/Asp.Net/SqlSugar/Utilities/CallContext.cs +++ b/Src/Asp.Net/SqlSugar/Utilities/CallContext.cs @@ -11,5 +11,6 @@ namespace SqlSugar internal class CallContext { public static ThreadLocal> ContextList = new ThreadLocal>(); + public static ThreadLocal> MapperExpression = new ThreadLocal>(); } }