diff --git a/Src/Asp.Net/SqlServerTest/UnitTest/UCustom012.cs b/Src/Asp.Net/SqlServerTest/UnitTest/UCustom012.cs index b30e6b290..26548e8a2 100644 --- a/Src/Asp.Net/SqlServerTest/UnitTest/UCustom012.cs +++ b/Src/Asp.Net/SqlServerTest/UnitTest/UCustom012.cs @@ -30,8 +30,8 @@ namespace OrmTest db.Insertable(new RoomA() { RoomId = 6, RoomName = "清华003厅", SchoolId = 2 }).ExecuteCommand(); - db.Insertable(new SchoolA() { SchoolId = 1, School_Name = "北大" }).ExecuteCommand(); - db.Insertable(new SchoolA() { SchoolId = 2, School_Name = "清华" }).ExecuteCommand(); + db.Insertable(new SchoolA() { SchoolId = 1, CityId= 1001001, School_Name = "北大" }).ExecuteCommand(); + db.Insertable(new SchoolA() { SchoolId = 2 , CityId=2,School_Name = "清华" }).ExecuteCommand(); db.Insertable(new StudentA() { StudentId = 1, SchoolId = 1, Name = "北大jack" }).ExecuteCommand(); db.Insertable(new StudentA() { StudentId = 2, SchoolId = 1, Name = "北大tom" }).ExecuteCommand(); @@ -65,6 +65,16 @@ namespace OrmTest .Mapper(it => it.SchoolA, it => it.SchoolId) .ToList(); + var list22 = db.Queryable() + //.Includes(it => it.SchoolA) + .Where(it=>it.SchoolA.City.Id== 1001001) + .ToList(); + var list33 = db.Queryable() + //.Includes(it => it.SchoolA) + .Where(it => it.SchoolA.SchoolId == 1) + .ToList(); + + Check.Exception(string.Join(",", list22.Select(it => it.StudentId)) != string.Join(",", list33.Select(it => it.StudentId)), "unit error"); var list3 = db.Queryable() .Includes(x => x.SchoolA, x => x.RoomList)//2个参数就是 then Include @@ -220,14 +230,19 @@ namespace OrmTest } public class SchoolA { - [SugarColumn(IsPrimaryKey = true)] + [SugarColumn(IsPrimaryKey = true,ColumnName = "schoolid")] public int SchoolId { get; set; } + [SugarColumn(IsNullable =true)] + public int CityId { get; set; } [SugarColumn( ColumnName = "SchoolName")] public string School_Name { get; set; } [Navigate(NavigateType.OneToMany,nameof(RoomA.SchoolId))] public List RoomList { get; set; } [Navigate(NavigateType.OneToMany, nameof(TeacherA.SchoolId))] public List TeacherList { get; set; } + [Navigate(NavigateType.OneToOne,nameof(CityId))] + public City City { get; set; } + } public class TeacherA { diff --git a/Src/Asp.Net/SqlSugar/ExpressionsToSql/ResolveItems/MemberExpressionResolve.cs b/Src/Asp.Net/SqlSugar/ExpressionsToSql/ResolveItems/MemberExpressionResolve.cs index 19748e87a..3ba2bd0bf 100644 --- a/Src/Asp.Net/SqlSugar/ExpressionsToSql/ResolveItems/MemberExpressionResolve.cs +++ b/Src/Asp.Net/SqlSugar/ExpressionsToSql/ResolveItems/MemberExpressionResolve.cs @@ -59,6 +59,7 @@ namespace SqlSugar else if (isMemberValue) { var nav = new OneToOneNavgateExpression(this.Context?.SugarContext?.Context); + var navN = new OneToOneNavgateExpressionN(this.Context?.SugarContext?.Context); if (nav.IsNavgate(expression)) { var value = nav.GetSql(); @@ -72,6 +73,19 @@ namespace SqlSugar AppendValue(parameter, isLeft, value); } } + else if (navN.IsNavgate(expression)) + { + var value = navN.GetMemberSql(); + this.Context.SingleTableNameSubqueryShortName = navN.shorName; + if (isSetTempData) + { + baseParameter.CommonTempData = value; + } + else + { + AppendValue(parameter, isLeft, value); + } + } else { ResolveMemberValue(parameter, baseParameter, isLeft, isSetTempData, expression); diff --git a/Src/Asp.Net/SqlSugar/ExpressionsToSql/ResolveItems/OneToOneNavgateExpressionN.cs b/Src/Asp.Net/SqlSugar/ExpressionsToSql/ResolveItems/OneToOneNavgateExpressionN.cs new file mode 100644 index 000000000..bd22892da --- /dev/null +++ b/Src/Asp.Net/SqlSugar/ExpressionsToSql/ResolveItems/OneToOneNavgateExpressionN.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; + +namespace SqlSugar +{ + internal class OneToOneNavgateExpressionN + { + #region Constructor + public string shorName { get; set; } + public EntityInfo entityInfo; + + public SqlSugarProvider context; + public OneToOneNavgateExpressionN(SqlSugarProvider context) + { + this.context = context; + } + + public bool IsNavgate(Expression expression) + { + var result = false; + var exp = expression; + if (exp is UnaryExpression) + { + exp = (exp as UnaryExpression).Operand; + } + if (exp is MemberExpression) + { + var memberExp = exp as MemberExpression; + var childExpression = memberExp.Expression; + result = ValidateIsJoinMember(result, memberExp, childExpression); + } + else if (exp is MethodCallExpression) + { + var memberExp = exp as MemberExpression; + var childExpression = memberExp.Expression; + result = ValidateIsJoinAny(result, memberExp, childExpression); + } + return result; + } + public MapperSql GetMemberSql() + { + MapperSql MapperSql = new MapperSql(); + var memberInfo = this.items.Where(it => it.Type == 1).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 = ""; + foreach (var item in joinInfos) + { + var shortName = item.ThisEntityInfo.DbTableName+i; + var pkColumn = item.ThisEntityInfo.Columns.FirstOrDefault(it => it.IsPrimarykey); + var 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}.{pkColumn.DbColumnName}={formInfo.ThisEntityInfo.DbTableName + (i-1)}.{navColum.DbColumnName}"; + queryable.AddJoinInfo(item.ThisEntityInfo.DbTableName, shortName,on , JoinType.Inner); + ++i; + lastShortName=shortName; + formInfo = item; + } + var selectProperyInfo=ExpressionTool.GetMemberName(memberInfo.Expression); + var selectColumnInfo = memberInfo.ParentEntityInfo.Columns.First(it => it.PropertyName == selectProperyInfo); + queryable.Select($" {lastShortName}.{selectColumnInfo.DbColumnName}"); + var last = subInfos.First(); + var FirstPkColumn = last.ThisEntityInfo.Columns.FirstOrDefault(it =>it.IsPrimarykey); + 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}.{PkColumn.DbColumnName} = {masterShortName}.{FirstPkColumn.DbColumnName} "); + MapperSql.Sql ="( " + queryable.ToSql().Key+" ) "; + return MapperSql; + } + #endregion + + #region All one to one + List items; + private bool ValidateIsJoinMember(bool result, MemberExpression memberExp, Expression childExpression) + { + if (childExpression != null && childExpression is MemberExpression) + { + var oldChildExpression = childExpression; + var child2Expression = (childExpression as MemberExpression).Expression; + if (child2Expression == null) + { + return false; + } + items = new List(); + items.Add(new ExpressionItems() { Type=1 , Expression= memberExp, ParentEntityInfo= this.context.EntityMaintenance.GetEntityInfo(oldChildExpression.Type )}); + items.Add(new ExpressionItems() { Type = 2, Expression = oldChildExpression, ThisEntityInfo=this.context.EntityMaintenance.GetEntityInfo(oldChildExpression.Type), ParentEntityInfo = this.context.EntityMaintenance.GetEntityInfo(child2Expression.Type) }); + 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; + } + #endregion + + #region One to one Last Method + private bool ValidateIsJoinAny(bool result, MemberExpression memberExp, Expression childExpression) + { + return false; + } + #endregion + + #region Helper + + 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 + + #region Entities + internal class ExpressionItems + { + /// + /// 0 memeber, 2 method ,3 class + /// + public int Type { get; set; } + public EntityInfo ParentEntityInfo { get; set; } + public EntityInfo ThisEntityInfo { get; set; } + public Expression Expression { get; set; } + public Navigate Nav + { + get + { + if (Expression is MemberExpression) + { + var name=(Expression as MemberExpression).Member.Name; + var navColumn = ParentEntityInfo.Columns.FirstOrDefault(it => it.PropertyName == name); + return navColumn==null?null:navColumn.Navigat; + } + return null; + } + } + + } + #endregion + } +} diff --git a/Src/Asp.Net/SqlSugar/SqlSugar.csproj b/Src/Asp.Net/SqlSugar/SqlSugar.csproj index ecb2ada72..188b9fd30 100644 --- a/Src/Asp.Net/SqlSugar/SqlSugar.csproj +++ b/Src/Asp.Net/SqlSugar/SqlSugar.csproj @@ -108,8 +108,9 @@ - - + + +