/// <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); }
// Cross Join private void AppendCrossJoin(ISqlBuilder jf, DbExpression dbExpression) { if (!usedKeyword) { jf.AppendNewLine(); jf.Append(_keywordName); usedKeyword = true; } else { jf.Append(','); jf.AppendNewLine(); jf.Append(_pad); } LambdaExpression lambda = dbExpression.Expressions[1] as LambdaExpression; Type type = lambda.Parameters[1].Type; var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); jf.AppendTable(typeRuntime.TableSchema, typeRuntime.TableName, typeRuntime.IsTemporary); string alias = _ag.GetTableAlias(lambda.Parameters[1]); jf.Append(' '); jf.Append(alias); }
/// <summary> /// 选择所有的字段 /// </summary> /// <param name="type">实体类型</param> /// <param name="alias">表别名</param> /// <param name="node">节点</param> /// <returns></returns> protected virtual Expression VisitAllMember(Type type, string alias, Expression node = null) { if (_groupBy != null && node != null && node.IsGrouping()) { // select g.Key LambdaExpression keySelector = _groupBy.Expressions[0] as LambdaExpression; return(this.Visit(keySelector.Body)); } else { TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); foreach (var item in typeRuntime.Members) { var m = item as FieldAccessorBase; if (m == null || !m.IsDbField) { continue; } _builder.AppendMember(alias, m.Member, type); this.AddSelectedColumn(m.Member, type); } } return(node); }
/// <summary> /// 实例化<see cref="TypeDeserializer"/> 类的新实例 /// </summary> /// <param name="context">当前查询上下文</param> /// <param name="reader">DataReader</param> /// <param name="map">SQL 命令描述</param> /// <param name="entityType">单个实体类型</param> internal TypeDeserializer_Internal(IDbContext context, IDataReader reader, IMapDescriptor map, Type entityType) { _map = map; _reader = reader; _context = context; _deserializers = new Dictionary <string, Func <IDataRecord, object> >(8); _manyNavigationKeys = new Dictionary <string, HashSet <string> >(8); _entityType = entityType; _isDynamic = _entityType == typeof(ExpandoObject) || _entityType == typeof(object); _typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(entityType); _deserializerImpl = ((DbQueryProvider)context.Provider).TypeDeserializerImpl; }
/// <summary> /// 更新自增列 /// </summary> /// <param name="dbQueryables">查询语义集合</param> /// <param name="identitys">自动ID</param> protected virtual void SetIdentityValue(List <object> dbQueryables, List <int> identitys) { if (identitys == null || identitys.Count == 0) { return; } int index = -1; foreach (var obj in dbQueryables) { var dbQuery = obj as IDbQueryable; if (dbQuery == null) { continue; } else if (dbQuery.DbExpressions == null) { continue; } else if (dbQuery.DbExpressions.Count == 0) { continue; } var dbExpression = dbQuery.DbExpressions.FirstOrDefault(x => x.DbExpressionType == DbExpressionType.Insert); if (dbExpression == null) { continue; } else if (dbExpression.Expressions == null) { continue; } else if (dbExpression.Expressions[0].NodeType != ExpressionType.Constant) { continue; } var entity = (dbExpression.Expressions[0] as ConstantExpression).Value; if (entity != null) { var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(entity.GetType()); if (typeRuntime.Identity != null) { index += 1; var identity = identitys[index]; typeRuntime.Identity.Invoke(entity, identity); } } } }
/// <summary> /// 解析全关联 /// </summary> protected virtual void AppendCrossJoin(DbExpression dbExpression) { var lambdaExp = dbExpression.Expressions[1] as LambdaExpression; Type type = lambdaExp.Parameters[1].Type; var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); _builder.Append(' '); _builder.AppendTable(typeRuntime.TableSchema, typeRuntime.TableName, typeRuntime.IsTemporary); string alias = _ag.GetTableAlias(lambdaExp.Parameters[1]); _builder.Append(' '); _builder.Append(alias); _builder.Append(' '); }
// 添加额外列,用来判断整个(左)连接记录是否为空 private void AddSplitOnColumn(MemberExpression m, string alias) { TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(m.Expression.Type); var attribute = typeRuntime.GetMemberAttribute <ForeignKeyAttribute>(m.Member.Name); string keyName = attribute.OuterKeys.FirstOrDefault(a => !a.StartsWith(AppConst.CONSTANT_FOREIGNKEY, StringComparison.Ordinal)); _builder.Append("CASE WHEN "); _builder.AppendMember(alias, keyName); _builder.Append(" IS NULL THEN NULL ELSE "); _builder.AppendMember(alias, keyName); _builder.Append(" END"); // 选择字段 string newName = _selectedColumns.Add(AppConst.NAVIGATION_SPLITON_NAME); _builder.AppendAs(newName); _builder.Append(','); _builder.AppendNewLine(); }
// Cross Join protected override void AppendCrossJoin(DbExpression dbExpression) { var lambdaExp = dbExpression.Expressions[1] as LambdaExpression; Type type = lambdaExp.Parameters[1].Type; var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); bool withNoLock = !typeRuntime.IsTemporary && _isNoLock && !string.IsNullOrEmpty(_withNoLock); _builder.Append(' '); _builder.AppendTable(typeRuntime.TableSchema, typeRuntime.TableName, typeRuntime.IsTemporary); string alias = _ag.GetTableAlias(lambdaExp.Parameters[1]); _builder.Append(' '); _builder.Append(alias); _builder.Append(' '); if (withNoLock) { _builder.Append(_withNoLock); _builder.Append(' '); } }
/// <summary> /// 访问参数列表 /// </summary> /// <param name="expression">将访问的表达式</param> /// <param name="isFilter">是否过滤条件</param> internal void VisitArgument(Expression expression, bool isFilter = false) { ITranslateContext context = _builder.TranslateContext; _tree.Select.Select = new DbExpression(DbExpressionType.Select, expression); // 可能会有几级嵌套,这里用 Builder.Ident 标记是第几层级 string[] subs = new[] { "p", "u", "v", "w", "x" }; var newContext = context != null?TranslateContext.Copy(context, subs[_builder.Indent]) : null; var cmd = Translator.Invoke(_tree.Select, _builder.Indent + 1, false, newContext) as DbSelectCommand; _builder.Append('('); _builder.Append(cmd.CommandText.Trim()); if (((DbSelectCommand)cmd).WhereFragment.Length > 0) { _builder.Append(" AND "); } else { _builder.Append("WHERE "); } var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(_tree.Entity != null ? _tree.Entity.GetType() : _tree.Select.From); foreach (var m in typeRuntime.KeyMembers) { _builder.AppendMember(string.Format("{0}0", subs[_builder.Indent]), m.Member, typeRuntime.Type); _builder.Append(" = "); _builder.AppendTable(typeRuntime.TableSchema, typeRuntime.TableName, typeRuntime.IsTemporary); _builder.Append('.'); _builder.AppendMember(null, m.Member, typeRuntime.Type); _builder.Append(" AND "); } _builder.Length -= 5; _builder.Append(')'); }
// 反序列化实体集合 T DeserializeCollection <T>() { object prevLine = null; bool isThisLine = false; var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo <T>(); var modelType = typeRuntime.GenericArguments[0]; var addMember = typeRuntime.GetMember("Add"); var collection = typeRuntime.Constructor.Invoke(); var deserializer = new TypeDeserializer_Internal(_context, _reader, _map, modelType); while (_reader.Read()) { object model = deserializer.Deserialize(prevLine, out isThisLine); if (!isThisLine) { prevLine = model; addMember.Invoke(collection, model); } } // 返回结果 return((T)collection); }
/// <summary> /// 添加导航属性关联 /// </summary> protected override void TanslateNavMember() { if (this.NavMembers == null || this.NavMembers.Count == 0) { return; } // 如果有一对多的导航属性,肯定会产生嵌套查询。那么内层查询别名肯定是t0,所以需要清掉 if (this.HasMany) { _aliasGenerator = new AliasGenerator(_aliasGenerator.ReserveQty); } //开始产生 USING 子句 ISqlBuilder jf = this.JoinFragment; int index = -1; // 未生成USING子句 if (_aliasGenerator.ReserveQty <= 1) { jf.AppendNewLine(); jf.Append(_keywordName); } else { jf.Append(','); jf.AppendNewLine(); } foreach (var nav in this.NavMembers) { index++; string key = nav.Key; MemberExpression m = nav.Expression; TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(m.Expression.Type); ForeignKeyAttribute attribute = typeRuntime.GetMemberAttribute <ForeignKeyAttribute>(m.Member.Name); string innerKey = string.Empty; string outerKey = key; string innerAlias = string.Empty; if (!m.Expression.Visitable()) { innerKey = m.Expression.NodeType == ExpressionType.Parameter ? (m.Expression as ParameterExpression).Name : (m.Expression as MemberExpression).Member.Name; } else { MemberExpression mLeft = null; if (m.Expression.NodeType == ExpressionType.MemberAccess) { mLeft = m.Expression as MemberExpression; } else if (m.Expression.NodeType == ExpressionType.Call) { mLeft = (m.Expression as MethodCallExpression).Object as MemberExpression; } string name = TypeRuntimeInfoCache.GetRuntimeInfo(mLeft.Type).TableFullName; innerAlias = _aliasGenerator.GetJoinTableAlias(name); if (string.IsNullOrEmpty(innerAlias)) { string keyLeft = mLeft.GetKeyWidthoutAnonymous(); if (this.NavMembers.Contains(keyLeft)) { innerKey = keyLeft; } innerAlias = _aliasGenerator.GetNavTableAlias(innerKey); } } string alias1 = !string.IsNullOrEmpty(innerAlias) ? innerAlias : _aliasGenerator.GetTableAlias(innerKey); string alias2 = _aliasGenerator.GetNavTableAlias(outerKey); // 补充与USING字符串同等间距的空白 if (_aliasGenerator.ReserveQty > 1 || index > 0) { jf.Append(_pad); } Type type = m.Type; var typeRumtime2 = TypeRuntimeInfoCache.GetRuntimeInfo(type); if (type.IsGenericType) { type = type.GetGenericArguments()[0]; } jf.AppendTable(typeRumtime2.TableSchema, typeRumtime2.TableName, typeRumtime2.IsTemporary); jf.Append(' '); jf.Append(alias2); if (_onPhrase.Length > 0) { _onPhrase.Append(" AND "); } for (int i = 0; i < attribute.InnerKeys.Length; i++) { if (attribute.InnerKeys[i].StartsWith(AppConst.CONSTANT_FOREIGNKEY, StringComparison.Ordinal)) { _onPhrase.Append(attribute.InnerKeys[i].Substring(7)); } else { _onPhrase.Append(alias1); _onPhrase.Append('.'); _onPhrase.AppendMember(attribute.InnerKeys[i]); } _onPhrase.Append(" = "); if (attribute.OuterKeys[i].StartsWith(AppConst.CONSTANT_FOREIGNKEY, StringComparison.Ordinal)) { _onPhrase.Append(attribute.OuterKeys[i].Substring(7)); } else { _onPhrase.Append(alias2); _onPhrase.Append('.'); _onPhrase.AppendMember(attribute.OuterKeys[i]); } } if (nav.Predicate != null) { string alias = _aliasGenerator.GetNavTableAlias(nav.Key); var visitor = new NavPredicateExpressionVisitor(_aliasGenerator, _onPhrase, alias); visitor.Visit(nav.Predicate); } if (index < this.NavMembers.Count - 1) { jf.Append(','); jf.AppendNewLine(); } } }
/// <summary> /// 添加导航属性关联 /// </summary> protected override void TanslateNavMember() { if (base.NavMembers == null || base.NavMembers.Count == 0) { return; } // 如果有一对多的导航属性,肯定会产生嵌套查询。那么内层查询别名肯定是t0,所以需要清掉 if (this.HasMany) { _ag = new AliasGenerator(_ag.ReserveQty); } //开始产生LEFT JOIN 子句 ISqlBuilder builder = this.JoinFragment; foreach (var nav in base.NavMembers) { string key = nav.Key; MemberExpression m = nav.Expression; TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(m.Expression.Type); ForeignKeyAttribute attribute = typeRuntime.GetMemberAttribute <ForeignKeyAttribute>(m.Member.Name); string innerKey = string.Empty; string outerKey = key; string innerAlias = string.Empty; if (!m.Expression.Visitable()) { innerKey = m.Expression.NodeType == ExpressionType.Parameter ? (m.Expression as ParameterExpression).Name : (m.Expression as MemberExpression).Member.Name; } else { MemberExpression mLeft = null; if (m.Expression.NodeType == ExpressionType.MemberAccess) { mLeft = m.Expression as MemberExpression; } else if (m.Expression.NodeType == ExpressionType.Call) { mLeft = (m.Expression as MethodCallExpression).Object as MemberExpression; } string name = TypeRuntimeInfoCache.GetRuntimeInfo(mLeft.Type).TableFullName; innerAlias = _ag.GetJoinTableAlias(name); if (string.IsNullOrEmpty(innerAlias)) { string keyLeft = mLeft.GetKeyWidthoutAnonymous(); if (base.NavMembers.Contains(keyLeft)) { innerKey = keyLeft; } innerAlias = _ag.GetNavTableAlias(innerKey); } } string alias1 = !string.IsNullOrEmpty(innerAlias) ? innerAlias : _ag.GetTableAlias(innerKey); string alias2 = _ag.GetNavTableAlias(outerKey); builder.AppendNewLine(); builder.Append("LEFT JOIN "); Type type = m.Type; if (type.IsGenericType) { type = type.GetGenericArguments()[0]; } var typeRuntime2 = TypeRuntimeInfoCache.GetRuntimeInfo(type); builder.AppendTable(typeRuntime2.TableSchema, typeRuntime2.TableFullName, typeRuntime2.IsTemporary); builder.Append(" "); builder.Append(alias2); bool withNoLock = !typeRuntime2.IsTemporary && _isNoLock && !string.IsNullOrEmpty(_withNoLock); if (withNoLock) { builder.Append(' '); builder.Append(_withNoLock); } builder.Append(" ON "); for (int i = 0; i < attribute.InnerKeys.Length; i++) { if (attribute.InnerKeys[i].StartsWith(AppConst.CONSTANT_FOREIGNKEY, StringComparison.Ordinal)) { builder.Append(attribute.InnerKeys[i].Substring(7)); } else { builder.Append(alias1); builder.Append('.'); builder.AppendMember(attribute.InnerKeys[i]); } builder.Append(" = "); if (attribute.OuterKeys[i].StartsWith(AppConst.CONSTANT_FOREIGNKEY, StringComparison.Ordinal)) { builder.Append(attribute.OuterKeys[i].Substring(7)); } else { builder.Append(alias2); builder.Append('.'); builder.AppendMember(attribute.OuterKeys[i]); } if (i < attribute.InnerKeys.Length - 1) { builder.Append(" AND "); } } if (nav.Predicate != null) { string alias = _ag.GetNavTableAlias(nav.Key); var visitor = new NavPredicateExpressionVisitor(_ag, builder, alias); visitor.Visit(nav.Predicate); } } }
/// <summary> /// 解析左关联 /// </summary> protected virtual void AppendLfInJoin(DbExpression dbExpression) { _builder.Append(' '); DbQueryable dbQueryable = (DbQueryable)((dbExpression.Expressions[0] as ConstantExpression).Value); dbQueryable.Parameterized = _builder.Parameterized; if (dbQueryable.DbExpressions.Count == 1 && dbQueryable.DbExpressions[0].DbExpressionType == DbExpressionType.GetTable) { // 区别 GetTable 有三个重载 var expressions = dbQueryable.DbExpressions[0].Expressions; if (expressions.Length == 2 && ((expressions[0] as ConstantExpression).Value as string) != null) { string text = (expressions[0] as ConstantExpression).Value as string; object[] @params = (expressions[1] as ConstantExpression).Value as object[]; var provider = ((DbQueryProvider)_builder.Provider); var context = _builder.TranslateContext; // 解析参数 object[] args = null; if (@params != null) { args = @params.Select(x => provider.Constor.GetSqlValue(x, context)).ToArray(); } string sql = text; if (args != null && args.Length > 0) { sql = string.Format(sql, args); } var cmd = new DbRawCommand(sql, context.Parameters, CommandType.Text); _builder.Append("("); _builder.Append(cmd.CommandText); _builder.AppendNewLine(); _builder.Append(')'); } else { Type type = dbExpression.Expressions[0].Type.GetGenericArguments()[0]; var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); _builder.AppendTable(typeRuntime.TableSchema, typeRuntime.TableName, typeRuntime.IsTemporary); } } else { // 嵌套 var cmd = dbQueryable.Translate(_builder.Indent + 1, false, _builder.TranslateContext); _builder.Append("("); _builder.Append(cmd.CommandText); _builder.AppendNewLine(); _builder.Append(')'); } var left = dbExpression.Expressions[1] as LambdaExpression; var right = dbExpression.Expressions[2] as LambdaExpression; // t0(t1) string alias = !(left.Body.NodeType == ExpressionType.New || left.Body.NodeType == ExpressionType.MemberInit) ? _ag.GetTableAlias(dbExpression.Expressions[2]) : _ag.GetTableAlias(right.Parameters[0]); _builder.Append(' '); _builder.Append(alias); _builder.Append(' '); // ON a.Name = b.Name AND a.Id = b.Id _builder.Append("ON "); if (left.Body.NodeType == ExpressionType.New) { var body1 = left.Body as NewExpression; var body2 = right.Body as NewExpression; for (int index = 0; index < body1.Arguments.Count; ++index) { base.Visit(body1.Arguments[index]); _builder.Append(" = "); base.Visit(body2.Arguments[index]); if (index < body1.Arguments.Count - 1) { _builder.Append(" AND "); } } } else if (left.Body.NodeType == ExpressionType.MemberInit) { var body1 = left.Body as MemberInitExpression; var body2 = right.Body as MemberInitExpression; for (int index = 0; index < body1.Bindings.Count; ++index) { base.Visit((body1.Bindings[index] as MemberAssignment).Expression); _builder.Append(" = "); base.Visit((body2.Bindings[index] as MemberAssignment).Expression); if (index < body1.Bindings.Count - 1) { _builder.Append(" AND "); } } } else { base.Visit(left.Body.ReduceUnary()); _builder.Append(" = "); base.Visit(right.Body.ReduceUnary()); } }
// LEFT OR INNER JOIN private void AppendLfInJoin(ISqlBuilder jf, ISqlBuilder on, DbExpression dbExpression) { DbQueryable dbQueryable = (DbQueryable)((dbExpression.Expressions[0] as ConstantExpression).Value); dbQueryable.Parameterized = jf.Parameterized; if (!usedKeyword) { jf.AppendNewLine(); jf.Append(_keywordName); usedKeyword = true; } else { jf.Append(','); jf.AppendNewLine(); jf.Append(_pad); } if (dbQueryable.DbExpressions.Count == 1 && dbQueryable.DbExpressions[0].DbExpressionType == DbExpressionType.GetTable) { // 区别 GetTable 有三个重载 var expressions = dbQueryable.DbExpressions[0].Expressions; if (expressions.Length == 2 && ((expressions[0] as ConstantExpression).Value as string) != null) { string text = (expressions[0] as ConstantExpression).Value as string; object[] @params = (expressions[1] as ConstantExpression).Value as object[]; var provider = ((DbQueryProvider)jf.Provider); var context = jf.TranslateContext; // 解析参数 object[] args = null; if (@params != null) { args = @params.Select(x => provider.Constor.GetSqlValue(x, context)).ToArray(); } string sql = text; if (args != null && args.Length > 0) { sql = string.Format(sql, args); } var cmd = new DbRawCommand(sql, context.Parameters, CommandType.Text); jf.Append("( "); jf.Append(_dbExpressionType == DbExpressionType.Delete ? cmd.CommandText.TrimStart() : cmd.CommandText); jf.Append(')'); } else { Type type = dbExpression.Expressions[0].Type.GetGenericArguments()[0]; var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); jf.AppendTable(typeRuntime.TableSchema, typeRuntime.TableName, typeRuntime.IsTemporary); } } else { // 嵌套 var cmd = dbQueryable.Translate(jf.Indent + _dbExpressionType == DbExpressionType.Delete ? 2 : 1, false, jf.TranslateContext); jf.Append("( "); jf.Append(_dbExpressionType == DbExpressionType.Delete ? cmd.CommandText.TrimStart() : cmd.CommandText); jf.Append(')'); } LambdaExpression left = dbExpression.Expressions[1] as LambdaExpression; LambdaExpression right = dbExpression.Expressions[2] as LambdaExpression; // t0(t1) string alias = !(left.Body.NodeType == ExpressionType.New || left.Body.NodeType == ExpressionType.MemberInit) ? _ag.GetTableAlias(dbExpression.Expressions[2]) : _ag.GetTableAlias(right.Parameters[0]); jf.Append(' '); jf.Append(alias); if (on.Length > 0) { on.Append(" AND "); } if (left.Body.NodeType == ExpressionType.New) { NewExpression body1 = left.Body as NewExpression; NewExpression body2 = right.Body as NewExpression; for (int index = 0; index < body1.Arguments.Count; ++index) { on.AppendMember(_ag, body1.Arguments[index]); on.Append(" = "); on.AppendMember(_ag, body2.Arguments[index]); if (index < body1.Arguments.Count - 1) { on.Append(" AND "); } } } else if (left.Body.NodeType == ExpressionType.MemberInit) { MemberInitExpression body1 = left.Body as MemberInitExpression; MemberInitExpression body2 = right.Body as MemberInitExpression; for (int index = 0; index < body1.Bindings.Count; ++index) { on.AppendMember(_ag, (body1.Bindings[index] as MemberAssignment).Expression); on.Append(" = "); on.AppendMember(_ag, (body2.Bindings[index] as MemberAssignment).Expression); if (index < body1.Bindings.Count - 1) { on.Append(" AND "); } } } else { on.AppendMember(_ag, left.Body.ReduceUnary()); on.Append(" = "); on.AppendMember(_ag, right.Body.ReduceUnary()); } }
/// <summary> /// 取指定类型的运行时元数据 /// </summary> /// <typeparam name="T">T</typeparam> /// <returns></returns> public static TypeRuntimeInfo GetRuntimeInfo <T>() => TypeRuntimeInfoCache.GetRuntimeInfo(typeof(T));
/// <summary> /// 取指定类型的运行时元数据 /// </summary> /// <param name="type">类型实例</param> /// <returns></returns> public static TypeRuntimeInfo GetRuntimeInfo(Type type) => TypeRuntimeInfoCache.GetRuntimeInfo(type, false);
// 获取 LEFT JOIN / INNER JOIN 子句关联表的的别名 private void PrepareJoinAlias(DbExpression dbExpression, AliasGenerator ag) { Type type = dbExpression.Expressions[0].Type.GetGenericArguments()[0]; string name = TypeRuntimeInfoCache.GetRuntimeInfo(type).TableFullName; string outerAlias = null; // on a.Name equals b.Name 或 on new{ Name = a.Name,Id=a.Id } equals new { Name = b.Name,Id=b.Id } var left = dbExpression.Expressions[1] as LambdaExpression; var right = dbExpression.Expressions[2] as LambdaExpression; if (left.Body.NodeType == ExpressionType.New) { var body1 = left.Body as NewExpression; var body2 = right.Body as NewExpression; for (int index = 0; index < body1.Arguments.Count; ++index) { ag.GetTableAlias(body1.Arguments[index]); } for (int index = 0; index < body2.Arguments.Count; ++index) { string alias = ag.GetTableAlias(body2.Arguments[index]); outerAlias = alias; // 记录显示指定的LEFT JOIN 表别名 ag.AddJoinTableAlias(name, alias); } } else if (left.Body.NodeType == ExpressionType.MemberInit) { var body1 = left.Body as MemberInitExpression; var body2 = right.Body as MemberInitExpression; for (int index = 0; index < body1.Bindings.Count; ++index) { ag.GetTableAlias((body1.Bindings[index] as MemberAssignment).Expression); } for (int index = 0; index < body2.Bindings.Count; ++index) { string alias = ag.GetTableAlias((body2.Bindings[index] as MemberAssignment).Expression); outerAlias = alias; // 记录显示指定的LEFT JOIN 表别名 ag.AddJoinTableAlias(name, alias); } } else { ag.GetTableAlias(dbExpression.Expressions[1]); string alias = ag.GetTableAlias(dbExpression.Expressions[2]); outerAlias = alias; // 记录显示指定的LEFT JOIN 表别名 ag.AddJoinTableAlias(name, alias); } // 由 GetTable 重载指定的导航属性表别名 if (dbExpression.Expressions.Length > 4) { if (string.IsNullOrEmpty(outerAlias) || outerAlias == AliasGenerator.EMPTYNAME) { var lambda = dbExpression.Expressions[3] as LambdaExpression; string alias = ag.GetTableAlias(lambda.Parameters[1]); outerAlias = alias; // 记录显示指定的LEFT JOIN 表别名 ag.AddJoinTableAlias(name, alias); } var member = (dbExpression.Expressions[4] as LambdaExpression).Body as MemberExpression; string keyId = member.GetKeyWidthoutAnonymous(); // 记录GetTable<,>(path)指定的表别名 ag.AddGetTableAlias(keyId, outerAlias); } }
/// <summary> /// 访问导航属性 /// </summary> /// <param name="expression">导航属性表达式</param> /// <param name="memberName">成员名称</param> /// <returns></returns> protected virtual string VisitNavMember(Expression expression, string memberName = null) { // 表达式 => b.Client.Address.AddressName Expression node = expression; Stack <NavMember> navStack = null; string alias = string.Empty; while (node != null && node.Visitable()) { if (node.NodeType != ExpressionType.MemberAccess) { break; } if (navStack == null) { navStack = new Stack <NavMember>(); } var member = node as MemberExpression; string key = member.GetKeyWidthoutAnonymous(); navStack.Push(new NavMember(key, member)); node = member.Expression; if (node.NodeType == ExpressionType.Call) { node = (node as MethodCallExpression).Object; } } if (navStack != null && navStack.Count > 0) { while (navStack != null && navStack.Count > 0) { NavMember nav = navStack.Pop(); Type type = nav.Expression.Type; if (type.IsGenericType) { type = type.GetGenericArguments()[0]; } var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); // 检查表达式是否由 GetTable<,>(path) 显式指定过别名 alias = _ag.GetGetTableAlias(nav.Key); if (string.IsNullOrEmpty(alias)) { // 如果没有,检查查询表达式是否显示指定该表关联 alias = _ag.GetJoinTableAlias(typeRuntime.TableFullName); } if (string.IsNullOrEmpty(alias)) { // 如果没有,则使用导航属性别名 alias = _ag.GetNavTableAlias(nav.Key); if (!this.NavMembers.Contains(nav.Key)) { this.NavMembers.Add(nav); } } // 例: a.Client.ClientId if (navStack.Count == 0 && !string.IsNullOrEmpty(memberName)) { _builder.AppendMember(alias, memberName); } } } else { // => SelectMany 也会产生类似 'b.Client.Address.AddressName' 这样的表达式 alias = _ag.GetTableAlias(expression); _builder.AppendMember(alias, memberName); } // Fix issue# Join 表达式显式指定导航属性时时,alias 为空 return(alias); }
/// <summary> /// 生成实体映射委托 /// </summary> /// <param name="type">实体类型</param> /// <param name="reader">数据读取器</param> /// <param name="columns">字段列描述</param> /// <param name="start">开始索引</param> /// <param name="end">结束索引</param> /// <returns></returns> public Func <IDataRecord, object> GetTypeDeserializer(Type type, IDataRecord reader, ColumnDescriptorCollection columns = null, int start = 0, int?end = null) { //// specify a new assembly name //var assemblyName = new AssemblyName("Riz.Deserialize"); //// create assembly builder //var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave); //// create module builder //var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, assemblyName.Name + ".dll", true); //// create type builder for a class //var typeBuilder = moduleBuilder.DefineType("Riz.Deserialize.Deserializer", TypeAttributes.Public); //// create method builder //var methodBuilder = typeBuilder.DefineMethod("GetModel", // MethodAttributes.Public | MethodAttributes.Static, // typeof(object), // new Type[] { typeof(IDataRecord) // }); TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); DynamicMethod dynamicMethod = new DynamicMethod(string.Format("Deserialize{0}", Guid.NewGuid()), typeof(object), new Type[] { typeof(IDataRecord) }, true); //ILGenerator il = methodBuilder.GetILGenerator(); ILGenerator il = dynamicMethod.GetILGenerator(); il.DeclareLocal(typeof(int)); // [0] int index il.DeclareLocal(type); // [1] {type} il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc_0); // 有参构造函数 ConstructorInfo specializedConstructor = null; if (type.IsValueType) { // 如果是值类型,则将值类型设置为空或者0 il.Emit(OpCodes.Ldloca_S, (byte)1); il.Emit(OpCodes.Initobj, type); } else { var ctor = typeRuntime.Constructor.Member; if (ctor.GetParameters().Length > 0) { specializedConstructor = ctor; } else { // 如果不是匿名类或者只有无参构造函数,则new一个对象 il.Emit(OpCodes.Newobj, ctor); il.Emit(OpCodes.Stloc_1); // [1] {type}=new {type} } } // try ##### il.BeginExceptionBlock(); if (specializedConstructor == null) { il.Emit(OpCodes.Ldloc_1); // [target] } // stack is now [target] Label finishLabel = il.DefineLabel(); Label loadNullLabel = il.DefineLabel(); int enumDeclareLocal = -1; if (end == null) { end = reader.FieldCount; } for (int index = start; index < end; index++) { // 找出对应DataReader中的字段名 string memberName = reader.GetName(index); if (columns != null) { ColumnDescriptor column = null; columns.TryGetValue(memberName, out column); memberName = column != null ? column.Name : string.Empty; } // 本地变量赋值 il.Emit(OpCodes.Ldc_I4, index); // [target][index] il.Emit(OpCodes.Stloc_0); // [target] // 如果导航属性分割列=DbNull,那么此导航属性赋空值 if (memberName == AppConst.NAVIGATION_SPLITON_NAME) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldc_I4, index); il.Emit(OpCodes.Callvirt, _isDBNull); il.Emit(OpCodes.Brtrue_S, loadNullLabel); } var m = typeRuntime.GetMember(memberName) as FieldAccessorBase; if (m == null) { continue; } if (specializedConstructor == null) { il.Emit(OpCodes.Dup); // stack is now [target][target] } // 数据字段类型 Type readerFieldType = reader.GetFieldType(index); Type realReaderFieldType = readerFieldType; // 实体属性类型 Type entityFieldType = m.CLRType; MethodInfo getFieldValue = this.GetReaderMethod(readerFieldType, entityFieldType, ref realReaderFieldType); if (readerFieldType != realReaderFieldType) { readerFieldType = realReaderFieldType; } Label isDbNullLabel = il.DefineLabel(); Label nextLoopLabel = il.DefineLabel(); // 判断字段是否是 DbNull il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldc_I4, index); il.Emit(OpCodes.Callvirt, _isDBNull); il.Emit(OpCodes.Brtrue, isDbNullLabel); // =>DataReader.Getxx(index) il.Emit(OpCodes.Ldarg_0); // stack is now [target][target][reader] if (getFieldValue.DeclaringType != typeof(IDataRecord)) { il.Emit(OpCodes.Castclass, getFieldValue.DeclaringType); // (SqlDataReader)IDataReader } il.Emit(OpCodes.Ldc_I4, index); // stack is now [target][target][reader][index] il.Emit(OpCodes.Callvirt, getFieldValue); // stack is now [target][target][value-or-object] if (entityFieldType == typeof(char) || entityFieldType == typeof(char?)) { il.EmitCall(OpCodes.Call, entityFieldType == typeof(char) ? _readChar : _readNullChar, null); // stack is now [target][target][typed-value] } else { // unbox nullable enums as the primitive, i.e. byte etc var nullUnderlyingType = Nullable.GetUnderlyingType(entityFieldType); var unboxType = nullUnderlyingType != null && nullUnderlyingType.IsEnum ? nullUnderlyingType : entityFieldType; if (unboxType.IsEnum) { Type numericType = Enum.GetUnderlyingType(unboxType); if (readerFieldType != typeof(string)) { ConvertBoxedStack(il, readerFieldType, unboxType, numericType); } else { if (enumDeclareLocal == -1) { enumDeclareLocal = il.DeclareLocal(typeof(string)).LocalIndex; } il.Emit(OpCodes.Castclass, typeof(string)); // stack is now [target][target][string] il.StoreLocal(enumDeclareLocal); // stack is now [target][target] il.Emit(OpCodes.Ldtoken, unboxType); // stack is now [target][target][enum-type-token] il.EmitCall(OpCodes.Call, _typeFromHandle, null); // stack is now [target][target][enum-type] il.LoadLocal(enumDeclareLocal); // stack is now [target][target][enum-type][string] il.Emit(OpCodes.Ldc_I4_1); // stack is now [target][target][enum-type][string][true] il.EmitCall(OpCodes.Call, _enumParse, null); // stack is now [target][target][enum-as-object] il.Emit(OpCodes.Unbox_Any, unboxType); // stack is now [target][target][typed-value] } // new Nullable<TValue>(TValue) if (nullUnderlyingType != null) { EmitNewNullable(il, entityFieldType); // stack is now [target][target][typed-value] } } else if (entityFieldType.FullName == _linqBinaryName) { var ctor = entityFieldType.GetConstructor(new Type[] { typeof(byte[]) }); il.Emit(OpCodes.Unbox_Any, typeof(byte[])); // stack is now [target][target][byte-array] il.Emit(OpCodes.Newobj, ctor); // stack is now [target][target][binary] } else { bool noBoxed = readerFieldType == unboxType || readerFieldType == nullUnderlyingType; // myFieldType和实体属性类型一致, 如果用 DataReader.GetValue,则要强制转换{object}为实体属性定义的类型 bool useCast = noBoxed && getFieldValue == _getValue && unboxType != typeof(object); if (useCast) { il.EmitCast(nullUnderlyingType ?? unboxType); // stack is now [target][target][typed-value] } // myFieldType和实体属性类型不一致,需要做类型转换 if (!noBoxed) { if (getFieldValue == _getValue && readerFieldType.IsValueType) { il.Emit(OpCodes.Unbox_Any, readerFieldType); // stack is now [target][target][value] } // not a direct match; need to tweak the unbox ConvertBoxedStack(il, readerFieldType, nullUnderlyingType ?? unboxType, null); } // new Nullable<TValue>(TValue) if (nullUnderlyingType != null) { EmitNewNullable(il, entityFieldType); // stack is now [target][target][typed-value] } } } if (specializedConstructor == null) { // Store the value in the property/field if (m.MemberType == MemberTypes.Field) { il.Emit(OpCodes.Stfld, m.Member as FieldInfo); // stack is now [target] } else { MethodInfo setMethod = (m as PropertyAccessor).Member.GetSetMethod(true); il.Emit(type.IsValueType ? OpCodes.Call : OpCodes.Callvirt, setMethod);// stack is now [target] } } il.Emit(OpCodes.Br_S, nextLoopLabel); // stack is now [target] il.MarkLabel(isDbNullLabel); // incoming stack: [target][target] if (specializedConstructor == null) { il.Emit(OpCodes.Pop); // stack is now [target] } else { // DbNull,将NULL或者0推到栈顶 if (!entityFieldType.IsValueType) { il.Emit(OpCodes.Ldnull); } else { int localIndex = il.DeclareLocal(entityFieldType).LocalIndex; il.LoadLocalAddress(localIndex); il.Emit(OpCodes.Initobj, entityFieldType); il.LoadLocal(localIndex); } } il.MarkLabel(nextLoopLabel); } if (specializedConstructor != null) { il.Emit(OpCodes.Newobj, specializedConstructor); } il.Emit(OpCodes.Stloc_1); // stack is empty // 直接跳到结束标签返回实体 il.Emit(OpCodes.Br, finishLabel); // 将 null 赋值给实体 il.MarkLabel(loadNullLabel); il.Emit(OpCodes.Pop); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Stloc_1); il.MarkLabel(finishLabel); il.BeginCatchBlock(typeof(Exception)); // stack is Exception il.Emit(OpCodes.Ldloc_0); // stack is Exception, index il.Emit(OpCodes.Ldarg_0); // stack is Exception, index, reader il.EmitCall(OpCodes.Call, _throwException, null); il.EndExceptionBlock(); il.Emit(OpCodes.Ldloc_1); // stack is [rval] il.Emit(OpCodes.Ret); //// then create the whole class type //typeBuilder.CreateType(); //// save assembly //assemblyBuilder.Save(assemblyName.Name + ".dll"); return((Func <IDataRecord, object>)dynamicMethod.CreateDelegate(typeof(Func <IDataRecord, object>))); }
// 获取成员包装器的外键特性 private ForeignKeyAttribute GetForeignKeyAttribute(FieldAccessorBase m, string memberName) { if (m == null) { throw new XFrameworkException("Member {0}.{1} not found.", _type.Name, memberName); } var attribute = m.GetCustomAttribute <ForeignKeyAttribute>(); if (attribute == null) { // 如果是属性,要求标记为 virtual var property = m as PropertyAccessor; if (property != null) { var getMethod = property.Member.GetGetMethod(true); if (getMethod != null && !getMethod.IsVirtual) { return(null); } } // 区分一对一和一对多导航属性 var navEntityType = m.CLRType.IsGenericType ? m.CLRType.GetGenericArguments()[0] : m.CLRType; var navTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(navEntityType); if (TypeUtils.IsCollectionType(m.CLRType)) { // 1:n 关系,外键实体必须持有当前实体的所有主键属性 int index = 0; string[] innerKeys = null; string[] outerKeys = null; foreach (FieldAccessorBase inner in this.KeyMembers) { if (!navTypeRuntime.Members.Contains(inner.Name)) { innerKeys = null; outerKeys = null; break; } else { var outer = navTypeRuntime.GetMember <FieldAccessorBase>(inner.Name); if (outer == null) { innerKeys = null; outerKeys = null; break; } else { if (innerKeys == null) { innerKeys = new string[this.KeyMembers.Count]; } if (outerKeys == null) { outerKeys = new string[this.KeyMembers.Count]; } innerKeys[index] = inner.Column != null && !string.IsNullOrEmpty(inner.Column.Name) ? inner.Column.Name : inner.Name; outerKeys[index] = inner.Column != null && !string.IsNullOrEmpty(inner.Column.Name) ? inner.Column.Name : inner.Name; } } index += 1; } if (innerKeys != null) { attribute = new ForeignKeyAttribute(innerKeys, outerKeys); } } else { // 1:1 关系,分两种情况 // 1. 当前实体持有外键实体的主键属性 // 2. 外键实体持有当前实体的主键属性 if (navTypeRuntime.KeyMembers.Count > 0) { int index = 0; string[] innerKeys = null; string[] outerKeys = null; foreach (FieldAccessorBase outer in navTypeRuntime.KeyMembers) { if (!this.Members.Contains(outer.Name)) { innerKeys = null; outerKeys = null; break; } else { var inner = this.GetMember <FieldAccessorBase>(outer.Name); if (inner == null) { innerKeys = null; outerKeys = null; break; } else { if (innerKeys == null) { innerKeys = new string[navTypeRuntime.KeyMembers.Count]; } if (outerKeys == null) { outerKeys = new string[navTypeRuntime.KeyMembers.Count]; } innerKeys[index] = inner.Column != null && !string.IsNullOrEmpty(inner.Column.Name) ? inner.Column.Name : inner.Name; outerKeys[index] = outer.Column != null && !string.IsNullOrEmpty(outer.Column.Name) ? outer.Column.Name : outer.Name; } } index += 1; } if (innerKeys != null) { attribute = new ForeignKeyAttribute(innerKeys, outerKeys); } } if (attribute == null) { int index = 0; string[] innerKeys = null; string[] outerKeys = null; foreach (FieldAccessorBase inner in this.KeyMembers) { if (!navTypeRuntime.Members.Contains(inner.Name)) { innerKeys = null; outerKeys = null; break; } else { var outer = navTypeRuntime.GetMember <FieldAccessorBase>(inner.Name); if (outer == null) { innerKeys = null; outerKeys = null; break; } else { if (innerKeys == null) { innerKeys = new string[this.KeyMembers.Count]; } if (outerKeys == null) { outerKeys = new string[this.KeyMembers.Count]; } innerKeys[index] = inner.Column != null && !string.IsNullOrEmpty(inner.Column.Name) ? inner.Column.Name : inner.Name; outerKeys[index] = inner.Column != null && !string.IsNullOrEmpty(inner.Column.Name) ? inner.Column.Name : inner.Name; } } index += 1; } if (innerKeys != null) { attribute = new ForeignKeyAttribute(innerKeys, outerKeys); } } } } return(attribute); }
// 反序列化导航属性 // @prevLine 前一行数据 // @isLine 是否同一行数据<同一父级> void Deserialize_Navigation(object prevModel, object model, string typeName, bool isThisLine) { // CRM_SaleOrder.Client // CRM_SaleOrder.Client.AccountList Type type = model.GetType(); TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); if (string.IsNullOrEmpty(typeName)) { typeName = type.Name; } //foreach (var kvp in _map.Navigations) foreach (var navigation in _map.SelectedNavs) { int start = -1; int end = -1; if (navigation.FieldCount > 0) { start = navigation.StartIndex; end = navigation.StartIndex + navigation.FieldCount; } string keyName = typeName + "." + navigation.Name; if (keyName != navigation.Key) { continue; } var navMember = typeRuntime.GetMember <FieldAccessorBase>(navigation.Name); if (navMember == null) { continue; } Type navType = navMember.CLRType; Func <IDataRecord, object> deserializer = null; TypeRuntimeInfo navTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(navType); object navCollection = null; if (TypeUtils.IsCollectionType(navType)) { // 1:n关系,导航属性为 List<T> navCollection = navMember.Invoke(model); if (navCollection == null) { // new 一个列表类型,如果导航属性定义为接口,则默认使用List<T>来实例化 TypeRuntimeInfo navTypeRuntime2 = navType.IsInterface ? TypeRuntimeInfoCache.GetRuntimeInfo(typeof(List <>).MakeGenericType(navTypeRuntime.GenericArguments[0])) : navTypeRuntime; navCollection = navTypeRuntime2.Constructor.Invoke(); navMember.Invoke(model, navCollection); } } if (!_deserializers.TryGetValue(keyName, out deserializer)) { deserializer = _deserializerImpl.GetTypeDeserializer(navType.IsGenericType ? navTypeRuntime.GenericArguments[0] : navType, _reader, _map.SelectedColumns, start, end); _deserializers[keyName] = deserializer; } // 如果整个导航链中某一个导航属性为空,则跳出递归 object navModel = deserializer(_reader); if (navModel != null) { if (navCollection == null) { // 非集合型导航属性 navMember.Invoke(model, navModel); // // // } else { // 集合型导航属性 if (prevModel != null && isThisLine) { #region 合并列表 // 判断如果属于同一个主表,则合并到上一行的当前明细列表 // 例:CRM_SaleOrder.Client.AccountList string[] keys = keyName.Split('.'); TypeRuntimeInfo curTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(_entityType); Type curType = curTypeRuntime.Type; MemberAccessorBase curAccessor = null; object curModel = prevModel; for (int i = 1; i < keys.Length; i++) { curAccessor = curTypeRuntime.GetMember(keys[i]); curModel = curAccessor.Invoke(curModel); if (curModel == null) { continue; } curType = curModel.GetType(); curTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(curType); // <<<<<<<<<<< 一对多对多关系 >>>>>>>>>> if (curType.IsGenericType && i != keys.Length - 1) { curTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(curType); //if (curTypeRuntime.GenericTypeDefinition == typeof(List<>)) if (TypeUtils.IsCollectionType(curType)) { var member_Count = curTypeRuntime.GetMember("get_Count"); int count = Convert.ToInt32(member_Count.Invoke(curModel)); // List.Count if (count > 0) { var member_Index = curTypeRuntime.GetMember("get_Item"); curModel = member_Index.Invoke(curModel, count - 1); // List[List.Count-1] curTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(curModel.GetType()); } else { // user.Roles.RoleFuncs=>Roles 列表有可能为空 curModel = null; break; } } } } if (curModel != null) { // 如果有两个以上的一对多关系的导航属性,那么在加入列表之前就需要剔除重复的实体 bool isAny = false; if (_map.SelectedNavs.Count > 1) { if (_manyNavigationNumber == null) { _manyNavigationNumber = _map.SelectedNavs.Count(x => HasMany(x.Member)); } if (_manyNavigationNumber != null && _manyNavigationNumber.Value > 1) { if (!_manyNavigationKeys.ContainsKey(keyName)) { _manyNavigationKeys[keyName] = new HashSet <string>(); } curTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(navModel.GetType()); StringBuilder keyBuilder = new StringBuilder(64); foreach (var m in curTypeRuntime.KeyMembers) { var value = m.Invoke(navModel); keyBuilder.AppendFormat("{0}={1};", m.Name, (value ?? string.Empty).ToString()); } string hash = keyBuilder.ToString(); if (_manyNavigationKeys[keyName].Contains(hash)) { isAny = true; } else { _manyNavigationKeys[keyName].Add(hash); } } } if (!isAny) { // 如果列表中不存在,则添加到上一行的相同导航列表中去 var member_Add = navTypeRuntime.GetMember("Add"); member_Add.Invoke(curModel, navModel); } } #endregion } else { // 此时的 navTypeRuntime 是 List<> 类型的运行时 // 先添加 List 列表 var member_Add = navTypeRuntime.GetMember("Add"); member_Add.Invoke(navCollection, navModel); var curTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(navModel.GetType()); StringBuilder keyBuilder = new StringBuilder(64); foreach (var m in curTypeRuntime.KeyMembers) { var value = m.Invoke(navModel); keyBuilder.AppendFormat("{0}={1};", m.Name, (value ?? string.Empty).ToString()); } string hash = keyBuilder.ToString(); if (!_manyNavigationKeys.ContainsKey(keyName)) { _manyNavigationKeys[keyName] = new HashSet <string>(); } if (!_manyNavigationKeys[keyName].Contains(hash)) { _manyNavigationKeys[keyName].Add(hash); } } } if (TypeUtils.IsCollectionType(navTypeRuntime.Type)) { navTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(navTypeRuntime.GenericArguments[0]); } if (navTypeRuntime.NavMembers.Count > 0) { Deserialize_Navigation(prevModel, navModel, keyName, isThisLine); } } } }
// 遍历 Include 包含的导航属性 private void VisitInclude() { if (_includes == null || _includes.Count == 0) { return; } foreach (var dbExpression in _includes) { Expression navExpression = dbExpression.Expressions[0]; Expression pickExpression = dbExpression.Expressions.Length > 1 ? dbExpression.Expressions[1] : null; Expression predicateExpression = dbExpression.Expressions.Length > 2 ? dbExpression.Expressions[2] : null; if (navExpression == null) { continue; } if (navExpression.NodeType == ExpressionType.Lambda) { navExpression = (navExpression as LambdaExpression).Body; } var memberExpression = navExpression as MemberExpression; if (memberExpression == null) { throw new XFrameworkException("Include expression body must be 'MemberExpression'."); } // 例:Include(a => a.Client.AccountList[0].Client) // 解析导航属性链 List <Expression> navStack = new List <Expression>(); while (memberExpression != null) { // a.Client 要求 <Client> 必须标明 ForeignKeyAttribute var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(memberExpression.Expression.Type); var attribute = typeRuntime.GetMemberAttribute <ForeignKeyAttribute>(memberExpression.Member.Name); if (attribute == null) { throw new XFrameworkException("ForeignKeyAttribute not found for include member {0}.{1}", typeRuntime.Type.Name, memberExpression.Member.Name); } MemberExpression m = null; navStack.Add(memberExpression); if (memberExpression.Expression.NodeType == ExpressionType.MemberAccess) { m = (MemberExpression)memberExpression.Expression; } else if (memberExpression.Expression.NodeType == ExpressionType.Call) { m = (memberExpression.Expression as MethodCallExpression).Object as MemberExpression; } //var m = memberExpression.Expression as MemberExpression; if (m == null) { navStack.Add(memberExpression.Expression); } memberExpression = m; } // 生成导航属性描述信息 string keyId = string.Empty; for (int index = navStack.Count - 1; index >= 0; index--) { Expression expression = navStack[index]; memberExpression = expression as MemberExpression; if (memberExpression == null) { continue; } if (_navDescriptors == null) { _navDescriptors = new NavDescriptorCollection(); } keyId = memberExpression.GetKeyWidthoutAnonymous(true); if (!_navDescriptors.Contains(keyId)) { // Fix issue# SplitOn 列占一个位 var nav = new NavDescriptor(keyId, memberExpression.Member); nav.StartIndex = index == 0 ? _selectedColumns.Count : -1; nav.FieldCount = index == 0 ? (GetFieldCount(pickExpression == null ? navExpression : pickExpression) + 1) : -1; _navDescriptors.Add(nav); } } this.VisitNavigation(memberExpression, true, pickExpression, predicateExpression); } }
// => Name = "Name" private void VisitMemberAssignmentImpl(Type newType, MemberAssignment m) { // 先添加当前字段的访问痕迹标记 _visitedStack.Add(m.Member, newType); if (TypeUtils.IsPrimitive(m.Member)) { this.VisitMemberBinding(m); // 选择字段 this.AddSelectedColumn(m.Member, newType); } else { // 非显式指定的导航属性需要有 ForeignKeyAttribute if (m.Expression.NodeType == ExpressionType.MemberAccess && m.Expression.Visitable()) { var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(newType); var attribute = typeRuntime.GetMemberAttribute <ForeignKeyAttribute>(m.Member.Name); // 不能当做导航属性的复杂字段 if (attribute == null) { return; } } // 生成导航属性描述集合,以类名.属性名做为键值 if (_navDescriptorKeys == null) { _navDescriptorKeys = new List <string>(); } if (_navDescriptors == null) { _navDescriptors = new NavDescriptorCollection(); } int num = _navDescriptorKeys.Count; string keyId = _navDescriptorKeys.Count > 0 ? _navDescriptorKeys[_navDescriptorKeys.Count - 1] : string.Empty; keyId = !string.IsNullOrEmpty(keyId) ? keyId + "." + m.Member.Name : m.Member.Name; var nav = new NavDescriptor(keyId, m.Member); if (!_navDescriptors.Contains(keyId)) { // Fix issue# spliton 列占一个位 nav.StartIndex = _selectedColumns.Count; nav.FieldCount = GetFieldCount(m.Expression) + (m.Expression.NodeType == ExpressionType.MemberAccess && m.Expression.Visitable() ? 1 : 0); _navDescriptors.Add(nav); _navDescriptorKeys.Add(keyId); } // 1.不显式指定导航属性,例:a.Client.ClientList // 2.表达式里显式指定导航属性,例:b if (m.Expression.NodeType == ExpressionType.MemberAccess) { this.VisitNavigation(m.Expression as MemberExpression, m.Expression.Visitable()); } else if (m.Expression.NodeType == ExpressionType.New) { this.VisitNewImpl(m.Expression as NewExpression, false); } else if (m.Expression.NodeType == ExpressionType.MemberInit) { this.VisitMemberInit(m.Expression as MemberInitExpression); } // 恢复访问链 // 在访问导航属性时可能是 Client.CloudServer,这时要恢复为 Client,以保证能访问 Client 的下一个导航属性 if (_navDescriptorKeys.Count != num) { _navDescriptorKeys.RemoveAt(_navDescriptorKeys.Count - 1); } } }