/// <summary> /// 获取字段或属性成员的 <see cref="ColumnAttribute"/> /// </summary> /// <param name="member">字段或属性成员</param> /// <param name="reflectedType">调用字段或属性成员的实际类型</param> /// <returns></returns> public static ColumnAttribute GetColumnAttribute(MemberInfo member, Type reflectedType) { if (member == null) { return(null); } if (reflectedType == null) { reflectedType = member.ReflectedType ?? member.DeclaringType; } ColumnAttribute column = null; if (!TypeUtils.IsAnonymousType(reflectedType) && !TypeUtils.IsPrimitiveType(reflectedType)) { var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(reflectedType); var m = typeRuntime.GetMember(member.Name); if (m != null && m is FieldAccessorBase) { column = (m as FieldAccessorBase).Column; } } return(column); }
// 判定 MemberInit 绑定是否声明了一对多关系的导航 private static bool HasMany(MemberInitExpression node) { for (int i = 0; i < node.Bindings.Count; i++) { // primitive 类型 Type type = (node.Bindings[i].Member as System.Reflection.PropertyInfo).PropertyType; if (TypeUtils.IsPrimitiveType(type)) { continue; } // complex 类型 if (TypeUtils.IsCollectionType(type)) { return(true); } MemberAssignment memberAssignment = node.Bindings[i] as MemberAssignment; if (memberAssignment != null && memberAssignment.Expression.NodeType == ExpressionType.MemberInit) { MemberInitExpression initExpression = memberAssignment.Expression as MemberInitExpression; if (HasMany(initExpression)) { return(true); } } } return(false); }
// 累加表达式中数据库字段的数量 private static int GetFieldCount(Expression node) { int num = 0; if (node.NodeType == ExpressionType.Lambda) { node = (node as LambdaExpression).Body; } switch (node.NodeType) { case ExpressionType.MemberInit: var initExpression = node as MemberInitExpression; foreach (var exp in initExpression.NewExpression.Arguments) { if (TypeUtils.IsPrimitiveType(exp.Type)) { num += 1; } else { num += _countComplex(exp); } } foreach (MemberAssignment b in initExpression.Bindings) { num += _countPrimitive(b.Member); } break; case ExpressionType.MemberAccess: var memberExpression = node as MemberExpression; num += _countComplex(memberExpression); break; case ExpressionType.New: var newExpression = node as NewExpression; //foreach (var exp in newExpression.Arguments) num += _countComplex(exp); if (newExpression.Members != null) { foreach (var member in newExpression.Members) { num += _countPrimitive(member); } } break; } return(num); }
/// <summary> /// 判断字段或属性成员的数据类型是否为 ORM 支持的基元类型 /// </summary> /// <param name="member">字段或属性成员</param> /// <returns></returns> public static bool IsPrimitive(MemberInfo member) { Type t = null; if (member != null && member.MemberType == MemberTypes.Field) { t = ((FieldInfo)member).FieldType; } else if (member != null && member.MemberType == MemberTypes.Property) { t = ((PropertyInfo)member).PropertyType; } return(t == null ? false : TypeUtils.IsPrimitiveType(t)); }
// 访问 New 表达式中的参数 private Expression VisitNewArgumentImpl(Type newType, MemberInfo member, Expression argument) { // 先添加当前字段的访问痕迹标记 if (member != null) { _visitedStack.Add(member, newType); } if (argument.NodeType == ExpressionType.Parameter) { //例: new Client(a) string alias = _ag.GetTableAlias(argument); this.VisitAllMember(argument.Type, alias); } else if (argument.CanEvaluate()) { //例: DateTime.Now _builder.Append(argument.Evaluate().Value, _visitedStack.Current); this.AddSelectedColumn(member, newType); } else if (argument.NodeType == ExpressionType.MemberAccess || argument.NodeType == ExpressionType.Call) { bool isNavigation = !argument.Type.IsEnum && !TypeUtils.IsPrimitiveType(argument.Type); if (isNavigation) { this.VisitNavigation(argument as MemberExpression, false); } else { // new Client(a.ClientId) this.Visit(argument); this.AddSelectedColumn(member, newType); } } else { if (member == null) { throw new XFrameworkException("{0} is not support for NewExpression's arguments."); } base.Visit(argument); this.AddSelectedColumn(member, newType); } return(argument); }
// 构造由一对多关系产生的嵌套查询 private static DbQuerySelectTree TryParseOutQuery(DbQuerySelectTree tree) { if (tree == null || tree.Select == null) { return(tree); } Expression select = tree.Select.Expressions[0]; List <DbExpression> includes = tree.Includes; Type fromType = tree.From; // 解析导航属性 如果有 1:n 的导航属性,那么查询的结果集的主记录将会有重复记录 // 这时就需要使用嵌套语义,先查主记录,再关联导航记录 Expression expression = select; var lambdaExpression = expression as LambdaExpression; if (lambdaExpression != null) { expression = lambdaExpression.Body; } var initExpression = expression as MemberInitExpression; var newExpression = expression as NewExpression; bool hasMany = DbQueryableParser.HasMany(includes); if (!hasMany) { hasMany = initExpression != null && HasMany(initExpression); } #region 嵌套语义 if (hasMany) { newExpression = initExpression != null ? initExpression.NewExpression : newExpression; List <MemberBinding> bindings = new List <MemberBinding>(); if (initExpression != null) { bindings = initExpression.Bindings.ToList(a => TypeUtils.IsPrimitiveType((a.Member as System.Reflection.PropertyInfo).PropertyType)); } if (newExpression != null || bindings.Count() > 0) { // 简化内层选择器,只选择最小字段,不选择导航字段,导航字段在外层加进去 initExpression = Expression.MemberInit(newExpression, bindings); lambdaExpression = Expression.Lambda(initExpression, lambdaExpression.Parameters); tree.Select = new DbExpression(DbExpressionType.Select, lambdaExpression); } tree.Includes = new List <DbExpression>(0); var result_Query = new DbQuerySelectTree(); result_Query.From = fromType; result_Query.Subquery = tree; result_Query.Joins = null; result_Query.OrderBys = null; result_Query.Includes = includes; result_Query.SelectHasMany = true; result_Query.Select = new DbExpression(DbExpressionType.Select, select); #region 排序 if (tree.OrderBys != null && tree.OrderBys.Count > 0) { // 是否有分页 bool havePaging = (tree.Take > 0 || tree.Skip > 0); if (!havePaging) { // 如果没有分页,则OrderBy需要放在外层 result_Query.OrderBys = tree.OrderBys; tree.OrderBys = new List <DbExpression>(0); } else { // 如果有分页,只有主表/用到的1:1从表放在内层,其它放在外层 List <DbExpression> innerOrderBy = null; foreach (var dbExpression in tree.OrderBys) { hasMany = HasMany(dbExpression.Expressions[0] as LambdaExpression); if (!hasMany) { if (innerOrderBy == null) { innerOrderBy = new List <DbExpression>(); } innerOrderBy.Add(dbExpression); } } if (innerOrderBy != null && innerOrderBy.Count > 0) { result_Query.OrderBys = tree.OrderBys; tree.OrderBys = innerOrderBy; } } } #endregion #region 分组 if (tree.GroupBy != null) { // 查看外层是否需要重新构造选择器。如果有分组并且有聚合函数,则需要重新构造选择器。否则外层解析不了聚合函数 // demo => line 1280 bool newSelector = bindings.Any(x => ((MemberAssignment)x).Expression.NodeType == ExpressionType.Call) || newExpression.Arguments.Any(x => x.NodeType == ExpressionType.Call); if (newSelector) { ParameterExpression newParameter = null; List <DbExpression> dbExpressions = null; if (result_Query.Includes != null && result_Query.Includes.Count > 0) { dbExpressions = result_Query.Includes; } else if (result_Query.OrderBys != null && result_Query.OrderBys.Count > 0) { dbExpressions = result_Query.OrderBys; } if (dbExpressions != null && dbExpressions.Count > 0) { newParameter = (dbExpressions[0].Expressions[0] as LambdaExpression).Parameters[0]; } // 1对多导航嵌套查询外层的的第一个表别名固定t0,参数名可随意 var parameterExpression = newParameter != null ? newParameter : Expression.Parameter(newExpression.Type, "__g"); bindings = bindings.ToList(x => (MemberBinding)Expression.Bind(x.Member, Expression.MakeMemberAccess(parameterExpression, x.Member))); List <Expression> arguments = null; if (newExpression.Members != null) { arguments = new List <Expression>(newExpression.Arguments.Count); for (int i = 0; i < newExpression.Arguments.Count; i++) { var member = newExpression.Members[i]; var arg = Expression.MakeMemberAccess(parameterExpression, member); arguments.Add(arg); } } newExpression = Expression.New(newExpression.Constructor, arguments, newExpression.Members); initExpression = Expression.MemberInit(newExpression, bindings); lambdaExpression = Expression.Lambda(initExpression, parameterExpression); result_Query.Select = new DbExpression(DbExpressionType.Select, lambdaExpression); } } #endregion tree = result_Query; } #endregion return(tree); }
/// <summary> /// 访问字段或者属性表达式 /// </summary> /// <param name="node">字段或者成员表达式</param> /// <returns></returns> protected override Expression VisitMember(MemberExpression node) { // 1.<>h__TransparentIdentifier3.b.Client.ClientName // 2.<>h__TransparentIdentifier3.b.Client.ClientName.Length // 3.<>h__TransparentIdentifier3.b.Client.Address.AddressName // 4.<>h__TransparentIdentifier3.b.ClientName // <>h__TransparentIdentifier2.<>h__TransparentIdentifier3.b.ClientName // <>h__TransparentIdentifier2.<>h__TransparentIdentifier3.b.Client.ClientName // <>h__TransparentIdentifier2.<>h__TransparentIdentifier3.b.Client.Address.AddressName // 5.b.ClientName if (node == null) { return(node); } // => a.ActiveDate == DateTime.Now => a.State == (byte)state if (node.CanEvaluate()) { return(this.VisitConstant(node.Evaluate())); } // => DateTime.Now if (node.Type == typeof(DateTime) && node.Expression == null) { return(this.VisitMethodCall(node, MethodCallType.MemberMember)); } // => a.Nullable.Value bool isNullable = node.Expression.Type.IsGenericType && node.Member.Name == "Value" && node.Expression.Type.GetGenericTypeDefinition() == typeof(Nullable <>); if (isNullable) { this.Visit(node.Expression); return(node); } // 记录访问成员栈 _visitedStack.Add(node); // => a.Name.Length if (TypeUtils.IsPrimitiveType(node.Expression.Type)) { return(this.VisitMethodCall(node, MethodCallType.MemberMember)); } // => <>h__3.b.ClientName if (!node.Expression.Visitable()) { _builder.AppendMember(_ag, node); return(node); } // => a.Accounts[0].Markets[0].MarketId // => b.Client.Address.AddressName Expression objExpression = node.Expression; bool isMethodCall = objExpression != null && objExpression.NodeType == ExpressionType.Call; if (isMethodCall) { MethodCallExpression methodExpression = objExpression as MethodCallExpression; bool isIndex = methodExpression.IsCollectionIndex(); if (isIndex) { objExpression = methodExpression.Object; } } // => b.Client.Address.AddressName this.VisitNavMember(objExpression, TypeUtils.GetFieldName(node.Member, node.Expression.Type)); return(node); }
/// <summary> /// 访问 Lambda 表达式,如 p=>p p=>p.t p=>p.Id /// </summary> /// <typeparam name="T">返回类型</typeparam> /// <param name="node">Lambda 表达式</param> /// <returns></returns> protected override Expression VisitLambda <T>(Expression <T> node) { LambdaExpression lambda = node as LambdaExpression; if (lambda.Body.NodeType == ExpressionType.Parameter) { // 例: a=> a Type type = lambda.Body.Type; string alias = _ag.GetTableAlias(lambda); this.VisitAllMember(type, alias); return(node); } else if (lambda.Body.CanEvaluate()) { // 例:a=>1 base.Visit(lambda.Body.Evaluate()); // 选择字段 string newName = _selectedColumns.Add(AppConst.CONSTANT_COLUMN_NAME); // 添加字段别名 _builder.AppendAs(newName); return(node); } else if (lambda.Body.NodeType == ExpressionType.MemberAccess) { // 例: t=> t.a // => SELECT a.ClientId Type type = lambda.Body.Type; if (!TypeUtils.IsPrimitiveType(type)) { return(this.VisitAllMember(type, _ag.GetTableAlias(lambda.Body), node)); } else { var newNode = this.VisitWithoutStack(_ => base.VisitLambda(node)); var memberExpression = lambda.Body as MemberExpression; string memberName = memberExpression.Member.Name; var srcDbExpressionType = _builder.TranslateContext.CurrentExpressionType; var srcIsOutermost = _builder.TranslateContext.CurrentIsOutermost; if (!(srcDbExpressionType != null && srcDbExpressionType == DbExpressionType.Select && srcIsOutermost != null && srcIsOutermost.Value)) { // 非外层字段,SELECT xx As name 的 name 使用数据库原生字段 memberName = TypeUtils.GetFieldName(memberExpression.Member, memberExpression.Expression.Type); } string newName = _selectedColumns.Add(memberName); return(newNode); } } else { // 例:a => a.DemoCode,选择字段仅选一个基元类型字段。 // 结果可能返回一个比如字符串类型列表 var newNode = base.VisitLambda(node); if (_selectedColumns.Count == 0) { // 选择字段 string newName = _selectedColumns.Add(AppConst.CONSTANT_COLUMN_NAME); // 添加字段别名 _builder.AppendAs(newName); } return(newNode); } }
/// <summary> /// 将 <see cref="IDataRecord"/> 上的当前行反序列化为实体 /// </summary> /// <param name="prevModel">前一行数据</param> /// <param name="isThisLine">是否同一行数据</param> /// <returns></returns> internal object Deserialize(object prevModel, out bool isThisLine) { isThisLine = false; #region 基元类型 if (_isPrimitive == null) { _isPrimitive = TypeUtils.IsPrimitiveType(_entityType) || _reader.GetName(0) == AppConst.AUTO_INCREMENT_NAME; } if (_isPrimitive.Value) { if (_reader.IsDBNull(0)) { return(TypeUtils.GetNullValue(_entityType)); //default(T); } var obj = _reader.GetValue(0); if (obj.GetType() != _entityType) { // fix#Nullable<T> issue if (!_entityType.IsGenericType) { obj = Convert.ChangeType(obj, _entityType); } else { Type type2 = _entityType.GetGenericTypeDefinition(); if (type2 != typeof(Nullable <>)) { throw new NotSupportedException(string.Format("type {0} not suppored.", type2.FullName)); } obj = Convert.ChangeType(obj, Nullable.GetUnderlyingType(_entityType)); } } return(obj); } #endregion #region 动态类型 if (_isDynamic) { ExpandoObject obj = new ExpandoObject(); var result = ((IDictionary <string, object>)obj); for (int i = 0; i < _reader.FieldCount; i++) { var value = _reader.GetValue(i); if (value == DBNull.Value) { value = null; } result.Add(_reader.GetName(i), value); } return((dynamic)obj); } #endregion #region 实体类型 object model = null; if (_map == null || _map.SelectedNavs == null || _map.SelectedNavs.Count == 0) { // 没有字段映射说明或者没有导航属性 if (_entityDeserializer == null) { _entityDeserializer = _deserializerImpl.GetTypeDeserializer(_entityType, _reader, _map != null ? _map.SelectedColumns : null, 0); } model = _entityDeserializer(_reader); } else { // 第一层 if (_entityDeserializer == null) { _entityDeserializer = _deserializerImpl.GetTypeDeserializer(_entityType, _reader, _map.SelectedColumns, 0, _map.SelectedNavs.MinIndex); } model = _entityDeserializer(_reader); // 若有 1:n 的导航属性,判断当前行数据与上一行数据是否相同 if (prevModel != null && _map.HasMany) { isThisLine = true; foreach (var m in _typeRuntime.KeyMembers) { var value1 = m.Invoke(prevModel); var value2 = m.Invoke(model); isThisLine = isThisLine && value1.Equals(value2); if (!isThisLine) { // Fix issue#换行时清空上一行的导航键缓存 _manyNavigationKeys.Clear(); break; } } } // 递归导航属性 this.Deserialize_Navigation(isThisLine ? prevModel : null, model, string.Empty, isThisLine); } return(model); #endregion }