/// <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) { column = m.Column; } } return(column); }
// Cross Join private void AppendCrossJoin(ISqlBuilder jf, DbExpression dbExpression, TableAliasCache aliases) { 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.AppendMember(typeRuntime.TableName, !typeRuntime.IsTemporary); string alias = aliases.GetTableAlias(lambda.Parameters[1]); jf.Append(' '); jf.Append(alias); }
/// <summary> /// 实例化<see cref="TypeDeserializer"/> 类的新实例 /// </summary> /// <param name="reader">DataReader</param> /// <param name="map">SQL 命令描述</param> internal TypeDeserializer(IDataReader reader, IMapping map) { _reader = reader; _map = map; _deserializers = new Dictionary <string, Func <IDataRecord, object> >(8); _manyNavvgationKeys = new Dictionary <string, HashSet <string> >(8); _isDynamic = typeof(T) == typeof(ExpandoObject) || typeof(T) == typeof(object); _typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo <T>(); }
/// <summary> /// 实例化<see cref="TypeDeserializer"/> 类的新实例 /// </summary> /// <param name="database">DataReader</param> /// <param name="reader">DataReader</param> /// <param name="map">SQL 命令描述</param> /// <param name="modelType">单个实体类型</param> internal TypeDeserializer_Internal(IDatabase database, IDataReader reader, IMapping map, Type modelType) { _map = map; _reader = reader; _database = database; _deserializerImpl = _database.TypeDeserializerImpl; _deserializers = new Dictionary <string, Func <IDataRecord, object> >(8); _manyNavigationKeys = new Dictionary <string, HashSet <string> >(8); _modelType = modelType; _isDynamic = _modelType == typeof(ExpandoObject) || _modelType == typeof(object); _typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(modelType); }
/// <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); } } } }
// Cross Join private void AppendCrossJoin(ISqlBuilder builder, DbExpression exp, TableAliasCache aliases) { LambdaExpression lambdaExp = exp.Expressions[1] as LambdaExpression; Type type = lambdaExp.Parameters[1].Type; var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); builder.Append(' '); builder.AppendMember(typeRuntime.TableName, !typeRuntime.IsTemporary); string alias = aliases.GetTableAlias(lambdaExp.Parameters[1]); builder.Append(' '); builder.Append(alias); builder.Append(' '); }
// 获取 LEFT JOIN / INNER JOIN 子句关联表的的别名 private void PrepareLfInJoinAlias(DbExpression dbExpression, TableAliasCache aliases) { Type type = dbExpression.Expressions[0].Type.GetGenericArguments()[0]; string name = TypeRuntimeInfoCache.GetRuntimeInfo(type).TableName; // on a.Name equals b.Name 或 on new{ Name = a.Name,Id=a.Id } equals new { Name = b.Name,Id=b.Id } LambdaExpression left = dbExpression.Expressions[1] as LambdaExpression; LambdaExpression right = dbExpression.Expressions[2] as LambdaExpression; 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) { aliases.GetTableAlias(body1.Arguments[index]); } for (int index = 0; index < body2.Arguments.Count; ++index) { string alias = aliases.GetTableAlias(body2.Arguments[index]); // 记录显示指定的LEFT JOIN 表别名 aliases.AddOrUpdateJoinTableAlias(name, alias); } } 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) { aliases.GetTableAlias((body1.Bindings[index] as MemberAssignment).Expression); } for (int index = 0; index < body2.Bindings.Count; ++index) { string alias = aliases.GetTableAlias((body2.Bindings[index] as MemberAssignment).Expression); // 记录显示指定的LEFT JOIN 表别名 aliases.AddOrUpdateJoinTableAlias(name, alias); } } else { aliases.GetTableAlias(dbExpression.Expressions[1]); string alias = aliases.GetTableAlias(dbExpression.Expressions[2]); // 记录显示指定的LEFT JOIN 表别名 aliases.AddOrUpdateJoinTableAlias(name, alias); } }
/// <summary> /// 访问表示方法调用的节点 /// </summary> /// <param name="node">方法调用节点</param> /// <returns></returns> public virtual Expression VisitMethodCall(MethodCallExpression node) { if (_typeRuntime == null) { _typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(this.GetType(), true); } MemberInvokerBase invoker = _typeRuntime.GetInvoker("Visit" + node.Method.Name); if (invoker == null) { throw new XFrameworkException("{0}.{1} is not supported.", node.Method.DeclaringType, node.Method.Name); } else { object exp = invoker.Invoke(this, new object[] { node }); return(exp as Expression); } }
// 添加额外列,用来判断整个(左)连接记录是否为空 private void AddSplitOnColumn(System.Reflection.MemberInfo member, string alias) { TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(member.DeclaringType); var fkAttribute = typeRuntime.GetMemberAttribute <ForeignKeyAttribute>(member.Name); string keyName = fkAttribute.OuterKeys.FirstOrDefault(a => !a.StartsWith(Constant.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 = _pickColumns.Add(Constant.NAVIGATION_SPLITON_NAME); //_builder.Append(caseWhen); _builder.AppendAs(newName); _builder.Append(','); _builder.AppendNewLine(); }
// 添加额外列,用来判断整个(左)连接记录是否为空 private void AppendNullColumn(System.Reflection.MemberInfo member, string alias) { TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(member.DeclaringType); var foreignKey = typeRuntime.GetInvokerAttribute <ForeignKeyAttribute>(member.Name); string keyName = foreignKey.OuterKeys[0]; _builder.Append("CASE WHEN "); _builder.AppendMember(alias, keyName); _builder.Append(" IS NULL THEN NULL ELSE "); _builder.AppendMember(alias, keyName); _builder.Append(" END"); // 选择字段 string newName = AddColumn(_columns, Constant.NAVIGATIONSPLITONNAME, null); //_builder.Append(caseWhen); _builder.AppendAs(newName); _builder.Append(','); _builder.AppendNewLine(); }
// 选择所有的字段 private 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); Dictionary <string, MemberInvokerBase> invokers = typeRuntime.Invokers; foreach (var m in invokers) { var invoker = m.Value; if (invoker != null && invoker.Column != null && invoker.Column.NoMapped) { continue; } if (invoker != null && invoker.ForeignKey != null) { continue; // 不加载导航属性 } if (invoker.Member.MemberType == System.Reflection.MemberTypes.Method) { continue; } _builder.AppendMember(alias, invoker.Member.Name); // 选择字段 string newName = AddColumn(_columns, invoker.Member.Name, alias); _builder.AppendAs(newName); _builder.Append(","); _builder.AppendNewLine(); } } return(node); }
// Cross Join private void AppendCrossJoin(ISqlBuilder builder, DbExpression exp, TableAlias aliases) { var lambdaExp = exp.Expressions[1] as LambdaExpression; Type type = lambdaExp.Parameters[1].Type; var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); bool withNoLock = !typeRuntime.IsTemporary && _context.NoLock && !string.IsNullOrEmpty(_provider.WidthNoLock); builder.Append(' '); builder.AppendMember(typeRuntime.TableName, !typeRuntime.IsTemporary); string alias = aliases.GetTableAlias(lambdaExp.Parameters[1]); builder.Append(' '); builder.Append(alias); builder.Append(' '); if (withNoLock) { builder.Append(_provider.WidthNoLock); builder.Append(' '); } }
/// <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 m in typeRuntime.Members) { if (m != null && m.Column != null && m.Column.NoMapped) { continue; } if (m != null && m.ForeignKey != null) { continue; // 不加载导航属性 } if (m.Member.MemberType == MemberTypes.Method) { continue; } _builder.AppendMember(alias, m.Member.Name); // 选择字段 string newName = _pickColumns.Add(m.Member.Name); _builder.AppendAs(newName); _builder.Append(","); _builder.AppendNewLine(); } } return(node); }
/// <summary> /// 访问参数列表 /// </summary> /// <param name="expression">将访问的表达式</param> /// <param name="isFilter">是否过滤条件</param> internal void VisitArgument(Expression expression, bool isFilter = false) { var token = _builder.Token; _dbQuery.Query.Select = new DbExpression(DbExpressionType.Select, expression); var cmd2 = ParseCommand(_dbQuery.Query, 1, false, new ResolveToken { Parameters = token.Parameters, AliasPrefix = "s", DbContext = _builder.Token.DbContext }) as MappingCommand; _builder.Append('('); _builder.Append(cmd2.CommandText.Trim()); if (((MappingCommand)cmd2).WhereFragment.Length > 0) { _builder.Append(" AND "); } else { _builder.Append("WHERE "); } var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(_dbQuery.Entity != null ? _dbQuery.Entity.GetType() : _dbQuery.Query.FromType); foreach (var m in typeRuntime.KeyMembers) { _builder.AppendMember("s0", m.Name); _builder.Append(" = "); _builder.AppendMember(typeRuntime.TableName); _builder.Append('.'); _builder.AppendMember(m.Name); _builder.Append(" AND "); } _builder.Length -= 5; _builder.Append(')'); }
internal void VisitArgument(Expression exp, bool wasFilter = false) { var token = _builder.Token; _uQueryInfo.SelectInfo.SelectExpression = new DbExpression(DbExpressionType.Select, exp); var cmd2 = (MappingCommand)ParseCommand(_uQueryInfo.SelectInfo, 1, false, new ResolveToken { Parameters = token.Parameters, TableAliasName = "s", IsDebug = wasFilter ? token.IsDebug : false }); _builder.Append('('); _builder.Append(cmd2.CommandText.Trim()); if (((MappingCommand)cmd2).WhereFragment.Length > 0) { _builder.Append(" AND "); } else { _builder.Append("WHERE "); } TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo <T>(); foreach (var invoker in typeRuntime.KeyInvokers) { _builder.AppendMember("s0", invoker.Name); _builder.Append(" = "); _builder.AppendMember(typeRuntime.TableName); _builder.Append('.'); _builder.AppendMember(invoker.Name); _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 member = typeRuntime.GetMember("Add"); var collection = typeRuntime.Constructor.Invoke(); TypeDeserializer_Internal deserializer = new TypeDeserializer_Internal(_database, _reader, _map, modelType); while (_reader.Read()) { object model = deserializer.Deserialize(prevLine, out isThisLine); if (!isThisLine) { prevLine = model; member.Invoke(collection, model); } } // 返回结果 return((T)collection); }
/// <summary> /// 获取指定成员的 <see cref="ColumnAttribute"/> /// </summary> /// <param name="member">成员</param> /// <param name="objType">成员所在类型</param> /// <returns></returns> public virtual ColumnAttribute GetColumnAttribute(MemberInfo member, Type objType) { Type dataType = TypeUtils.GetDataType(member); if (dataType == null) { return(null); } ColumnAttribute column = null; Type type = objType != null ? objType : (member.ReflectedType != null ? member.ReflectedType : member.DeclaringType); if (type != null && !TypeUtils.IsAnonymousType(type) && !TypeUtils.IsPrimitiveType(type)) { TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); var invoker = typeRuntime.GetInvoker(member.Name); if (invoker != null) { column = invoker.Column; } } return(column); }
/// <summary> /// 添加导航属性关联 /// </summary> protected override void ResoveNavMember() { if (this.NavMembers == null || this.NavMembers.Count == 0) { return; } // 如果有一对多的导航属性,肯定会产生嵌套查询。那么内层查询别名肯定是t0,所以需要清掉 if (this.HasMany) { _aliases = new TableAlias(_aliases.HoldQty); } //开始产生 USING 子句 ISqlBuilder jf = this.JoinFragment; int index = -1; // 未生成USING子句 if (_aliases.HoldQty <= 1) { jf.AppendNewLine(); jf.Append(_keywordName); } else { jf.Append(','); jf.AppendNewLine(); } foreach (var nav in this.NavMembers) { index++; string key = nav.KeyId; 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).TableName; innerAlias = _aliases.GetJoinTableAlias(name); if (string.IsNullOrEmpty(innerAlias)) { string keyLeft = mLeft.GetKeyWidthoutAnonymous(); if (this.NavMembers.Contains(keyLeft)) { innerKey = keyLeft; } innerAlias = _aliases.GetNavTableAlias(innerKey); } } string alias1 = !string.IsNullOrEmpty(innerAlias) ? innerAlias : _aliases.GetTableAlias(innerKey); string alias2 = _aliases.GetNavTableAlias(outerKey); // 补充与USING字符串同等间距的空白 if (_aliases.HoldQty > 1 || index > 0) { jf.Append(_pad); } Type type = m.Type; var typeRumtime2 = TypeRuntimeInfoCache.GetRuntimeInfo(type); if (type.IsGenericType) { type = type.GetGenericArguments()[0]; } jf.AppendMember(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(Constant.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(Constant.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 = _aliases.GetNavTableAlias(nav.KeyId); var visitor = new NavPredicateExpressionVisitor(_provider, _aliases, nav.Predicate, alias); visitor.Write(_onPhrase); } if (index < this.NavMembers.Count - 1) { jf.Append(','); jf.AppendNewLine(); } } }
// 添加导航属性关联 protected virtual void AppendNavigation() { if (this._navMembers == null || this._navMembers.Count == 0) { return; } // 如果有一对多的导航属性,肯定会产生嵌套查询。那么内层查询别名肯定是t0,所以需要清掉 if (this.HasManyNavigation) { _aliases = new TableAliasCache(_aliases.Declared); } //开始产生LEFT JOIN 子句 ISqlBuilder builder = this.JoinFragment; foreach (var kvp in _navMembers) { string key = kvp.Key; MemberExpression m = kvp.Value; TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(m.Expression.Type); ForeignKeyAttribute attribute = typeRuntime.GetInvokerAttribute <ForeignKeyAttribute>(m.Member.Name); string innerKey = string.Empty; string outerKey = key; string innerAlias = string.Empty; if (!m.Expression.Acceptable()) { 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).TableName; innerAlias = _aliases.GetJoinTableAlias(name); if (string.IsNullOrEmpty(innerAlias)) { string keyLeft = mLeft.GetKeyWidthoutAnonymous(); if (_navMembers.ContainsKey(keyLeft)) { innerKey = keyLeft; } innerAlias = _aliases.GetNavigationTableAlias(innerKey); } } string alias1 = !string.IsNullOrEmpty(innerAlias) ? innerAlias : _aliases.GetTableAlias(innerKey); string alias2 = _aliases.GetNavigationTableAlias(outerKey); builder.AppendNewLine(); builder.Append("LEFT JOIN "); Type type = m.Type; if (type.IsGenericType) { type = type.GetGenericArguments()[0]; } var typeRuntime2 = TypeRuntimeInfoCache.GetRuntimeInfo(type); builder.AppendMember(typeRuntime2.TableName, !typeRuntime2.IsTemporary); builder.Append(" "); builder.Append(alias2); builder.Append(" ON "); for (int i = 0; i < attribute.InnerKeys.Length; i++) { builder.Append(alias1); builder.Append('.'); builder.AppendMember(attribute.InnerKeys[i]); builder.Append(" = "); builder.Append(alias2); builder.Append('.'); builder.AppendMember(attribute.OuterKeys[i]); if (i < attribute.InnerKeys.Length - 1) { builder.Append(" AND "); } } } }
// LEFT OR INNER JOIN private void AppendLfInJoin(ISqlBuilder jf, ISqlBuilder on, DbExpression dbExpression, TableAliasCache aliases) { IDbQueryable sQuery = (IDbQueryable)((dbExpression.Expressions[0] as ConstantExpression).Value); if (!usedKeyword) { jf.AppendNewLine(); jf.Append(_keywordName); usedKeyword = true; } else { jf.Append(','); jf.AppendNewLine(); jf.Append(_pad); } if (sQuery.DbExpressions.Count == 1 && sQuery.DbExpressions[0].DbExpressionType == DbExpressionType.GetTable) { Type type = dbExpression.Expressions[0].Type.GetGenericArguments()[0]; var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); jf.AppendMember(typeRuntime.TableName, !typeRuntime.IsTemporary); } else { // 嵌套 var cmd = sQuery.Resolve(jf.Indent + _dbExpressionType == DbExpressionType.Delete ? 2 : 1, false, jf.Token); 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) ? aliases.GetTableAlias(dbExpression.Expressions[2]) : aliases.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(aliases, body1.Arguments[index]); on.Append(" = "); on.AppendMember(aliases, 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(aliases, (body1.Bindings[index] as MemberAssignment).Expression); on.Append(" = "); on.AppendMember(aliases, (body2.Bindings[index] as MemberAssignment).Expression); if (index < body1.Bindings.Count - 1) { on.Append(" AND "); } } } else { on.AppendMember(aliases, left.Body.ReduceUnary()); on.Append(" = "); on.AppendMember(aliases, right.Body.ReduceUnary()); } }
// LEFT OR INNER JOIN private void AppendLfInJoin(ISqlBuilder builder, DbExpression dbExpression, TableAlias aliases) { bool withNoLock = false; builder.Append(' '); IDbQueryable dbQuery = (IDbQueryable)((dbExpression.Expressions[0] as ConstantExpression).Value); if (dbQuery.DbExpressions.Count == 1 && dbQuery.DbExpressions[0].DbExpressionType == DbExpressionType.GetTable) { Type type = dbExpression.Expressions[0].Type.GetGenericArguments()[0]; var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); builder.AppendMember(typeRuntime.TableName, !typeRuntime.IsTemporary); withNoLock = !typeRuntime.IsTemporary && _context.NoLock && !string.IsNullOrEmpty(_provider.WidthNoLock); } else { // 嵌套 var cmd = dbQuery.Resolve(builder.Indent + 1, false, builder.Token); 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) ? aliases.GetTableAlias(dbExpression.Expressions[2]) : aliases.GetTableAlias(right.Parameters[0]); builder.Append(' '); builder.Append(alias); builder.Append(' '); if (withNoLock) { builder.Append(_provider.WidthNoLock); 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) { builder.AppendMember(aliases, body1.Arguments[index]); builder.Append(" = "); builder.AppendMember(aliases, 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) { builder.AppendMember(aliases, (body1.Bindings[index] as MemberAssignment).Expression); builder.Append(" = "); builder.AppendMember(aliases, (body2.Bindings[index] as MemberAssignment).Expression); if (index < body1.Bindings.Count - 1) { builder.Append(" AND "); } } } else { builder.AppendMember(aliases, left.Body.ReduceUnary()); builder.Append(" = "); builder.AppendMember(aliases, right.Body.ReduceUnary()); } }
/// <summary> /// 取指定类型的运行时元数据 /// </summary> /// <param name="type">类型实例</param> /// <returns></returns> public static TypeRuntimeInfo GetRuntimeInfo(Type type) { return(TypeRuntimeInfoCache.GetRuntimeInfo(type, false)); }
// 反序列化导航属性 // @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.PickNavDescriptors) { 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.KeyId) { continue; } var navAccessor = typeRuntime.GetMember(navigation.Name); if (navAccessor == null) { continue; } Type navType = navAccessor.DataType; Func <IDataRecord, object> deserializer = null; TypeRuntimeInfo navTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(navType); object navCollection = null; //if (navType.IsGenericType && navTypeRuntime.GenericTypeDefinition == typeof(List<>)) if (TypeUtils.IsCollectionType(navType)) { // 1:n关系,导航属性为 List<T> navCollection = navAccessor.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(); navAccessor.Invoke(model, navCollection); } } if (!_deserializers.TryGetValue(keyName, out deserializer)) { deserializer = _deserializerImpl.GetTypeDeserializer(navType.IsGenericType ? navTypeRuntime.GenericArguments[0] : navType, _reader, _map.PickColumns, start, end); _deserializers[keyName] = deserializer; } // 如果整个导航链中某一个导航属性为空,则跳出递归 object navModel = deserializer(_reader); if (navModel != null) { if (navCollection == null) { // 非集合型导航属性 navAccessor.Invoke(model, navModel); // // // } else { // 集合型导航属性 if (prevModel != null && isThisLine) { #region 合并列表 // 判断如果属于同一个主表,则合并到上一行的当前明细列表 // 例:CRM_SaleOrder.Client.AccountList string[] keys = keyName.Split('.'); TypeRuntimeInfo curTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo <T>(); 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 m = curTypeRuntime.GetMember("get_Count"); int count = Convert.ToInt32(m.Invoke(curModel)); // List.Count if (count > 0) { var m2 = curTypeRuntime.GetMember("get_Item"); curModel = m2.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.PickNavDescriptors.Count > 1) { if (_manyNavigationNumber == null) { _manyNavigationNumber = _map.PickNavDescriptors.Count(x => IsManyNavigation(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 myAddMethod = navTypeRuntime.GetMember("Add"); myAddMethod.Invoke(curModel, navModel); } } #endregion } else { // 此时的 navTypeRuntime 是 List<> 类型的运行时 // 先添加 List 列表 var myAddMethod = navTypeRuntime.GetMember("Add"); myAddMethod.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 (navTypeRuntime.GenericTypeDefinition == typeof(List<>)) navTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(navTypeRuntime.GenericArguments[0]); if (TypeUtils.IsCollectionType(navTypeRuntime.Type)) { navTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(navTypeRuntime.GenericArguments[0]); } if (navTypeRuntime.NavMembers.Count > 0) { Deserialize_Navigation(prevModel, navModel, keyName, isThisLine); } } } }
/// <summary> /// 取指定类型的运行时元数据 /// </summary> /// <typeparam name="T">T</typeparam> /// <returns></returns> public static TypeRuntimeInfo GetRuntimeInfo <T>() { return(TypeRuntimeInfoCache.GetRuntimeInfo(typeof(T))); }
// 遍历 Include 包含的导航属性 private void VisitInclude() { if (_include == null || _include.Count == 0) { return; } foreach (var dbExpression in _include) { Expression exp = dbExpression.Expressions[0]; if (exp == null) { continue; } if (exp.NodeType == ExpressionType.Lambda) { exp = (exp as LambdaExpression).Body; } MemberExpression memberExpression = exp as MemberExpression; if (memberExpression == null) { throw new XFrameworkException("Include expression body must be 'MemberExpression'."); } // 例:Include(a => a.Client.AccountList[0].Client) // 解析导航属性链 List <Expression> chain = new List <Expression>(); while (memberExpression != null) { // a.Client 要求 <Client> 必须标明 ForeignKeyAttribute TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(memberExpression.Expression.Type); ForeignKeyAttribute attribute = typeRuntime.GetInvokerAttribute <ForeignKeyAttribute>(memberExpression.Member.Name); if (attribute == null) { throw new XFrameworkException("Include member {{{0}}} must mark 'ForeignKeyAttribute'.", memberExpression); } MemberExpression m = null; chain.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) { chain.Add(memberExpression.Expression); } memberExpression = m; } // 生成导航属性描述信息 string keyName = string.Empty; for (int i = chain.Count - 1; i >= 0; i--) { Expression expression = chain[i]; memberExpression = expression as MemberExpression; if (memberExpression == null) { continue; } keyName = memberExpression.GetKeyWidthoutAnonymous(true); if (!_navigations.ContainsKey(keyName)) { // fix issue# XC 列占一个位 Navigation descriptor = new Navigation(keyName, memberExpression.Member); descriptor.Start = i == 0 ? _columns.Count : -1; //_columns.Count; descriptor.FieldCount = i == 0 ? (GetFieldCount(exp) + 1) : -1; //i == 0 ? (GetFieldCount(exp) + 1) : 1;//-1; _navigations.Add(keyName, descriptor); } } this.VisitNavigation(memberExpression, true); } }
// {new App() {Id = p.Id}} private Expression VisitMemberInitImpl(MemberInitExpression node, bool topBinding) { // 如果有一对多的导航属性会产生嵌套的SQL,这时需要强制主表选择的列里面必须包含导航外键 // TODO #对 Bindings 进行排序,保证导航属性的赋值一定要最后面# // 未实现,在书写表达式时人工保证 ## if (node.NewExpression != null) { this.VisitNewImpl(node.NewExpression); } if (_navChainHopper.Count == 0) { _navChainHopper.Add(node.Type.Name); } for (int i = 0; i < node.Bindings.Count; i++) { MemberAssignment binding = node.Bindings[i] as MemberAssignment; if (binding == null) { throw new XFrameworkException("Only 'MemberAssignment' binding supported."); } Type propertyType = (node.Bindings[i].Member as System.Reflection.PropertyInfo).PropertyType; bool isNavigation = !TypeUtils.IsPrimitiveType(propertyType); #region 一般属性 // 非导航属性 if (!isNavigation) { if (binding.Expression.CanEvaluate()) { _builder.Append(binding.Expression.Evaluate().Value, binding.Member, node.Type); } else { base.VisitMemberBinding(binding); } // 选择字段 string alias = _visitedMark.Current != null?_aliases.GetTableAlias(_visitedMark.Current) : null; string newName = AddColumn(_columns, binding.Member.Name, alias); // 添加字段别名 _builder.AppendAs(newName); _builder.Append(','); _builder.AppendNewLine(); } #endregion #region 导航属性 else { // 非显式指定的导航属性需要有 ForeignKeyAttribute if (binding.Expression.NodeType == ExpressionType.MemberAccess && binding.Expression.Acceptable()) { TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(binding.Member.DeclaringType); var attribute = typeRuntime.GetInvokerAttribute <ForeignKeyAttribute>(binding.Member.Name); if (attribute == null) { throw new XFrameworkException("Complex property {{{0}}} must mark 'ForeignKeyAttribute' ", binding.Member.Name); } } // 生成导航属性描述集合,以类名.属性名做为键值 int n = _navChainHopper.Count; string keyName = _navChainHopper.Count > 0 ? _navChainHopper[_navChainHopper.Count - 1] : string.Empty; keyName = !string.IsNullOrEmpty(keyName) ? keyName + "." + binding.Member.Name : binding.Member.Name; Navigation descriptor = new Navigation(keyName, binding.Member); if (!_navigations.ContainsKey(keyName)) { // fix issue# XC 列占一个位 descriptor.Start = _columns.Count; descriptor.FieldCount = GetFieldCount(binding.Expression) + (binding.Expression.NodeType == ExpressionType.MemberAccess && binding.Expression.Acceptable() ? 1 : 0); _navigations.Add(keyName, descriptor); _navChainHopper.Add(keyName); } // 1.不显式指定导航属性,例:a.Client.ClientList // 2.表达式里显式指定导航属性,例:b if (binding.Expression.NodeType == ExpressionType.MemberAccess) { this.VisitNavigation(binding.Expression as MemberExpression, binding.Expression.Acceptable()); } else if (binding.Expression.NodeType == ExpressionType.New) { this.VisitNewImpl(binding.Expression as NewExpression); } else if (binding.Expression.NodeType == ExpressionType.MemberInit) { this.VisitMemberInitImpl(binding.Expression as MemberInitExpression, false); } // 恢复访问链 // 在访问导航属性时可能是 Client.CloudServer,这时要恢复为 Client,以保证能访问 Client 的下一个导航属性 if (_navChainHopper.Count != n) { _navChainHopper.RemoveAt(_navChainHopper.Count - 1); } } #endregion base._visitedMark.Clear(); } return(node); }
//static ConstructorInfo _ctorXmlReader = typeof(XmlTextReader).GetConstructor(new[] { typeof(string), typeof(XmlNodeType), typeof(XmlParserContext) }); //static ConstructorInfo _ctorSqlXml = typeof(System.Data.SqlTypes.SqlXml).GetConstructor(new[] { typeof(System.Xml.XmlTextReader) }); internal static Func <IDataRecord, object> GetTypeDeserializer(Type type, IDataRecord reader, IDictionary <string, Column> columns = null, int start = 0, int?end = null) { //// specify a new assembly name //var assemblyName = new AssemblyName("Kitty"); //// create assembly builder //var assemblyBuilder = AppDomain.CurrentDomain // .DefineDynamicAssembly(assemblyName, // AssemblyBuilderAccess.RunAndSave); //// create module builder //var moduleBuilder = // assemblyBuilder.DefineDynamicModule( // "KittyModule", "Kitty.exe"); //// create type builder for a class //var typeBuilder = // moduleBuilder.DefineType( // "HelloKittyClass", TypeAttributes.Public); //// create method builder //var methodBuilder = typeBuilder.DefineMethod( // "SayHelloMethod", // MethodAttributes.Public | MethodAttributes.Static, // typeof(object), // new Type[] { typeof(IDataRecord) }); TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); DynamicMethod method = new DynamicMethod(string.Format("Deserialize{0}", Guid.NewGuid()), typeof(object), new Type[] { typeof(IDataRecord) }, true); //ILGenerator il = methodBuilder.GetILGenerator(); ILGenerator il = method.GetILGenerator(); il.DeclareLocal(typeof(int)); il.DeclareLocal(type); il.DeclareLocal(typeof(object)); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Stloc_2); // 有参构造函数 ConstructorInfo specializedConstructor = null; if (type.IsValueType) { // 如果是值类型,则将值类型设置为空或者0 il.Emit(OpCodes.Ldloca_S, (byte)1); il.Emit(OpCodes.Initobj, type); } else { var ctor = typeRuntime.ConstructInvoker.Constructor; if (ctor.GetParameters().Length > 0) { specializedConstructor = ctor; } else { // 如果不是匿名类或者只有无参构造函数,则new一个对象 il.Emit(OpCodes.Newobj, ctor); il.Emit(OpCodes.Stloc_1); } } // 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) { Column 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] //il.Emit(OpCodes.Ldnull); // [target][null] //il.Emit(OpCodes.Stloc_2); // [target] // 如果导航属性分割列=DbNull,那么此导航属性赋空值 if (memberName == Constant.NAVIGATIONSPLITONNAME) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldc_I4, index); il.Emit(OpCodes.Callvirt, _isDBNull); il.Emit(OpCodes.Brtrue_S, loadNullLabel); } var invoker = typeRuntime.GetInvoker(memberName); if (invoker == null) { continue; } if (specializedConstructor == null) { il.Emit(OpCodes.Dup); // stack is now [target][target] } Type columnType = reader.GetFieldType(index); Type memberType = invoker.DataType; Label isDbNullLabel = il.DefineLabel(); Label nextLoopLabel = il.DefineLabel(); MethodInfo readMethod = GetReaderMethod(columnType); // 判断字段是否是 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] il.Emit(OpCodes.Ldc_I4, index); // stack is now [target][target][reader][index] il.Emit(OpCodes.Callvirt, readMethod); // stack is now [target][target][value-or-object] //// =>object = value,记录当前处理的值 //// 除了string类型之外,其它的都需要要装箱,这里会有性能损失,100w笔记录大概会损失0.8s~ //bool useBoxed = readMethod != _getValue && columnType != typeof(string); //il.Emit(OpCodes.Dup); // stack is now [target][target][value-or-object][value-or-object] //if (useBoxed) il.Emit(OpCodes.Box, columnType); // stack is now [target][target][value-or-object][value-as-object] //else il.Emit(OpCodes.Castclass, typeof(object)); // stack is now [target][target][value][value-as-object] //il.Emit(OpCodes.Stloc_2); // stack is now [target][target][value-or-object] if (memberType == typeof(char) || memberType == typeof(char?)) { il.EmitCall(OpCodes.Call, memberType == 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(memberType); var unboxType = nullUnderlyingType != null && nullUnderlyingType.IsEnum ? nullUnderlyingType : memberType; if (unboxType.IsEnum) { Type numericType = Enum.GetUnderlyingType(unboxType); if (columnType != typeof(string)) { BoxConvert(il, columnType, 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] } if (nullUnderlyingType != null) { var ctor = memberType.GetConstructor(new[] { nullUnderlyingType }); il.Emit(OpCodes.Newobj, ctor); // stack is now [target][target][typed-value] } } else if (memberType.FullName == _linqBinaryName) { var ctor = memberType.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 { TypeCode dataTypeCode = Type.GetTypeCode(columnType), unboxTypeCode = Type.GetTypeCode(unboxType); bool useOriginal = columnType == unboxType || dataTypeCode == unboxTypeCode || dataTypeCode == Type.GetTypeCode(nullUnderlyingType); // fix issue# oracle guid useOriginal = useOriginal && !((nullUnderlyingType ?? unboxType) == typeof(Guid) && columnType == typeof(byte[])); if (useOriginal) { if (readMethod == _getValue && unboxType != typeof(object)) { il.EmitCast(nullUnderlyingType ?? unboxType); // stack is now [target][target][typed-value] } } else { if (readMethod == _getValue && columnType.IsValueType)// stack is now [target][target][value] { il.Emit(OpCodes.Unbox_Any, columnType); } // not a direct match; need to tweak the unbox BoxConvert(il, columnType, nullUnderlyingType ?? unboxType, null); } if (nullUnderlyingType != null) { var ctor = unboxType.GetConstructor(new[] { nullUnderlyingType }); il.Emit(OpCodes.Newobj, ctor); // stack is now [target][target][typed-value] } } } if (specializedConstructor == null) { // Store the value in the property/field if (invoker.MemberType == MemberTypes.Field) { il.Emit(OpCodes.Stfld, invoker.Member as FieldInfo); // stack is now [target] } else { MethodInfo setMethod = (invoker as PropertyInvoker).SetMethod; 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 (!invoker.DataType.IsValueType) { il.Emit(OpCodes.Ldnull); } else { int localIndex = il.DeclareLocal(invoker.DataType).LocalIndex; il.LoadLocalAddress(localIndex); il.Emit(OpCodes.Initobj, invoker.DataType); 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.Ldloc_2); // stack is Exception, index, value 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 //var helloKittyClassType = typeBuilder.CreateType(); //// set entry point for this assembly //assemblyBuilder.SetEntryPoint( // helloKittyClassType.GetMethod("SayHelloMethod")); //// save assembly //assemblyBuilder.Save("Kitty.exe"); return((Func <IDataRecord, object>)method.CreateDelegate(typeof(Func <IDataRecord, object>))); }
// 添加导航属性关联 protected override void AppendNavigation() { if (this.NavMembers == null || this.NavMembers.Count == 0) { return; } // 如果有一对多的导航属性,肯定会产生嵌套查询。那么内层查询别名肯定是t0,所以需要清掉 if (this.HasMany) { _aliases = new TableAliasCache(_aliases.Declared); } //开始产生 USING 子句 ISqlBuilder jf = this.JoinFragment; int index = -1; // 未生成USING子句 if (_aliases.Declared <= 1) { jf.AppendNewLine(); jf.Append(_keywordName); } else { jf.Append(','); jf.AppendNewLine(); } foreach (var kvp in this.NavMembers) { index++; string key = kvp.Key; MemberExpression m = kvp.Value; TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(m.Expression.Type); ForeignKeyAttribute attribute = typeRuntime.GetInvokerAttribute <ForeignKeyAttribute>(m.Member.Name); string innerKey = string.Empty; string outerKey = key; string innerAlias = string.Empty; if (!m.Expression.Acceptable()) { 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).TableName; innerAlias = _aliases.GetJoinTableAlias(name); if (string.IsNullOrEmpty(innerAlias)) { string keyLeft = mLeft.GetKeyWidthoutAnonymous(); if (this.NavMembers.ContainsKey(keyLeft)) { innerKey = keyLeft; } innerAlias = _aliases.GetNavigationTableAlias(innerKey); } } string alias1 = !string.IsNullOrEmpty(innerAlias) ? innerAlias : _aliases.GetTableAlias(innerKey); string alias2 = _aliases.GetNavigationTableAlias(outerKey); // 补充与USING字符串同等间距的空白 if (_aliases.Declared > 1 || index > 0) { jf.Append(_pad); } Type type = m.Type; var typeRumtime2 = TypeRuntimeInfoCache.GetRuntimeInfo(type); if (type.IsGenericType) { type = type.GetGenericArguments()[0]; } jf.AppendMember(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++) { _onPhrase.Append(alias1); _onPhrase.Append('.'); _onPhrase.AppendMember(attribute.InnerKeys[i]); _onPhrase.Append(" = "); _onPhrase.Append(alias2); _onPhrase.Append('.'); _onPhrase.AppendMember(attribute.OuterKeys[i]); } if (index < this.NavMembers.Count - 1) { jf.Append(','); jf.AppendNewLine(); } } }
/// <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, DbColumnCollection columns = null, int start = 0, int?end = null) { //// specify a new assembly name //var assemblyName = new AssemblyName("TZM.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("TZM.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 method = new DynamicMethod(string.Format("Deserialize{0}", Guid.NewGuid()), typeof(object), new Type[] { typeof(IDataRecord) }, true); //ILGenerator il = methodBuilder.GetILGenerator(); ILGenerator il = method.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.Constructor; 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) { DbColumn 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 == Constant.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); if (m == null) { continue; } if (specializedConstructor == null) { il.Emit(OpCodes.Dup); // stack is now [target][target] } // 数据字段类型 Type myFieldType = reader.GetFieldType(index); Type myFieldType2 = myFieldType; // 实体属性类型 Type memberType = m.DataType; MethodInfo getFieldValue = this.GetReaderMethod(myFieldType, memberType, ref myFieldType2); if (myFieldType != myFieldType2) { myFieldType = myFieldType2; } 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 (memberType == typeof(char) || memberType == typeof(char?)) { il.EmitCall(OpCodes.Call, memberType == 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(memberType); var unboxType = nullUnderlyingType != null && nullUnderlyingType.IsEnum ? nullUnderlyingType : memberType; if (unboxType.IsEnum) { Type numericType = Enum.GetUnderlyingType(unboxType); if (myFieldType != typeof(string)) { ConvertBox(il, myFieldType, 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, memberType); // stack is now [target][target][typed-value] } } else if (memberType.FullName == _linqBinaryName) { var ctor = memberType.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 = myFieldType == unboxType || myFieldType == 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 && myFieldType.IsValueType) { il.Emit(OpCodes.Unbox_Any, myFieldType); // stack is now [target][target][value] } // not a direct match; need to tweak the unbox ConvertBox(il, myFieldType, nullUnderlyingType ?? unboxType, null); } // new Nullable<TValue>(TValue) if (nullUnderlyingType != null) { EmitNewNullable(il, memberType); // 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).SetMethod; 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 (!m.DataType.IsValueType) { il.Emit(OpCodes.Ldnull); } else { int localIndex = il.DeclareLocal(m.DataType).LocalIndex; il.LoadLocalAddress(localIndex); il.Emit(OpCodes.Initobj, m.DataType); 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>)method.CreateDelegate(typeof(Func <IDataRecord, object>))); }
/// <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> stack = null; string alias = string.Empty; while (node != null && node.Visitable()) { if (node.NodeType != ExpressionType.MemberAccess) { break; } if (stack == null) { stack = new Stack <NavMember>(); } var member = node as MemberExpression; var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(member.Expression.Type); ForeignKeyAttribute attribute = typeRuntime.GetMemberAttribute <ForeignKeyAttribute>(member.Member.Name); if (attribute == null) { break; } string key = member.GetKeyWidthoutAnonymous(); stack.Push(new NavMember(key, member)); node = member.Expression; if (node.NodeType == ExpressionType.Call) { node = (node as MethodCallExpression).Object; } } if (stack != null && stack.Count > 0) { while (stack != null && stack.Count > 0) { NavMember nav = stack.Pop(); Type type = nav.Expression.Type; if (type.IsGenericType) { type = type.GetGenericArguments()[0]; } var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); // 检查表达式是否由 GetTable<,>(path) 显式指定过别名 alias = _aliases.GetGetTableAlias(nav.KeyId); if (string.IsNullOrEmpty(alias)) { // 如果没有,检查查询表达式是否显示指定该表关联 alias = _aliases.GetJoinTableAlias(typeRuntime.TableName); } if (string.IsNullOrEmpty(alias)) { // 如果没有,则使用导航属性别名 alias = _aliases.GetNavTableAlias(nav.KeyId); if (!_navMembers.Contains(nav.KeyId)) { _navMembers.Add(nav); } } // 例: a.Client.ClientId if (stack.Count == 0 && !string.IsNullOrEmpty(memberName)) { _builder.AppendMember(alias, memberName); } } } else { // => SelectMany 也会产生类似 'b.Client.Address.AddressName' 这样的表达式 alias = _aliases.GetTableAlias(expression); _builder.AppendMember(alias, memberName); } // Fix issue# Join 表达式显式指定导航属性时时,alias 为空 return(alias); }