/// <summary> /// Parse Inline ParameterMap /// </summary> /// <param name="dataExchangeFactory">The data exchange factory.</param> /// <param name="statementId">The statement id.</param> /// <param name="statement">The statement.</param> /// <param name="sqlStatement">The SQL statement.</param> /// <returns>A new sql command text.</returns> internal static SqlText ParseInlineParameterMap(DataExchangeFactory dataExchangeFactory, string statementId, IStatement statement, string sqlStatement) { string newSql = sqlStatement; List<ParameterProperty> mappingList = new List<ParameterProperty>(); Type parameterClassType = null; if (statement != null) { parameterClassType = statement.ParameterClass; } if (sqlStatement.Contains(NEW_BEGIN_TOKEN)) { // V3 parameter syntax //@{propertyName,column=string,type=string,dbtype=string,direction=[Input/Output/InputOutput],nullValue=string,handler=string} if (newSql != null) { string toAnalyse = newSql; int start = toAnalyse.IndexOf(NEW_BEGIN_TOKEN); int end = toAnalyse.IndexOf(NEW_END_TOKEN); StringBuilder newSqlBuffer = new StringBuilder(); while (start > -1 && end > start) { string prepend = toAnalyse.Substring(0, start); string append = toAnalyse.Substring(end + NEW_END_TOKEN.Length); //EmailAddress,column=string,type=string,dbType=Varchar,[email protected] string parameter = toAnalyse.Substring(start + NEW_BEGIN_TOKEN.Length, end - start - NEW_BEGIN_TOKEN.Length); ParameterProperty mapping = NewParseMapping(parameter, parameterClassType, dataExchangeFactory, statementId); mappingList.Add(mapping); newSqlBuffer.Append(prepend); newSqlBuffer.Append(MARK_TOKEN); toAnalyse = append; start = toAnalyse.IndexOf(NEW_BEGIN_TOKEN); end = toAnalyse.IndexOf(NEW_END_TOKEN); } newSqlBuffer.Append(toAnalyse); newSql = newSqlBuffer.ToString(); } } else { #region old syntax StringTokenizer parser = new StringTokenizer(sqlStatement, PARAMETER_TOKEN, true); StringBuilder newSqlBuffer = new StringBuilder(); string token = null; string lastToken = null; IEnumerator enumerator = parser.GetEnumerator(); while (enumerator.MoveNext()) { token = (string)enumerator.Current; if (PARAMETER_TOKEN.Equals(lastToken)) { // Double token ## = # if (PARAMETER_TOKEN.Equals(token)) { newSqlBuffer.Append(PARAMETER_TOKEN); token = null; } else { ParameterProperty mapping = null; if (token.IndexOf(PARAM_DELIM) > -1) { mapping = OldParseMapping(token, parameterClassType, dataExchangeFactory); } else { mapping = NewParseMapping(token, parameterClassType, dataExchangeFactory, statementId); } mappingList.Add(mapping); newSqlBuffer.Append(MARK_TOKEN + " "); enumerator.MoveNext(); token = (string)enumerator.Current; if (!PARAMETER_TOKEN.Equals(token)) { throw new DataMapperException("Unterminated inline parameter in mapped statement (" + statementId + ")."); } token = null; } } else { if (!PARAMETER_TOKEN.Equals(token)) { newSqlBuffer.Append(token); } } lastToken = token; } newSql = newSqlBuffer.ToString(); #endregion old syntax } ParameterProperty[] mappingArray = mappingList.ToArray(); SqlText sqlText = new SqlText(); sqlText.Text = newSql; sqlText.Parameters = mappingArray; return sqlText; }
/// <summary> /// Parse dynamic tags /// </summary> /// <param name="statementConfig">The statement config.</param> /// <param name="dynamic">The dynamic.</param> /// <param name="sqlBuffer">The SQL buffer.</param> /// <param name="isDynamic">if set to <c>true</c> [is dynamic].</param> /// <param name="postParseRequired">if set to <c>true</c> [post parse required].</param> /// <param name="statement">The statement.</param> /// <returns></returns> private bool ParseDynamicTags( IConfiguration statementConfig, IDynamicParent dynamic, StringBuilder sqlBuffer, bool isDynamic, bool postParseRequired, IStatement statement) { //具体文本的集合 可能是需要拼接成完整的SQL语句 ConfigurationCollection children = statementConfig.Children; int count = children.Count; for (int i = 0; i < count; i++) { IConfiguration child = children[i]; if (child.Type == ConfigConstants.ELEMENT_TEXT || child.Type == ConfigConstants.ELEMENT_CDATA) { //第一步处理 获取当前文本的一个值 并处理"\r\n" string childValueString = child.Value; if (statement.PreserveWhitespace) { childValueString = childValueString .Replace('\n', ' ').Replace('\r', ' ').Replace('\t', ' ').Trim(); } //第二部处理 将处理的当前一个部分SQL语句放入到SqlText类中 SqlText sqlText = null; if (postParseRequired) { sqlText = new SqlText(); sqlText.Text = childValueString; } else { //分析SQL语句中的参数 例如# # ,@{}等内部参数 最后的结果是一个语句保存 和 参数列表在SqlText类中 sqlText = InlineParameterMapParser.ParseInlineParameterMap(modelStore.DataExchangeFactory, statementConfig.Id, null, childValueString); } //将此次分析的SQL语句结果保存到dynamic类对象中 可能需要添加多次 dynamic.AddChild(sqlText);//按顺序放置 最后拼接即可 //sqlBuffer字符串拼接每一部分的sql语句 最后是当前节点的完整语句 sqlBuffer.Append(" " + childValueString); } else if (child.Type == ConfigConstants.ELEMENT_SELECTKEY || child.Type == ConfigConstants.ELEMENT_INCLUDE) { //此处没有处理代码 } else { //从deSerializerFactory工厂类的字典serializerMap中获取对应的处理IDeSerializer类 IDeSerializer serializer = deSerializerFactory.GetDeSerializer(child.Type);//child.Type就是节点的名 if (serializer != null) { isDynamic = true; SqlTag tag; //当前child是一个element 进行解析 tag = serializer.Deserialize(child); //添加到IList<ISqlChild> children中 dynamic.AddChild(tag); if (child.Children.Count > 0) { //递归处理子节点 注意是子节点Tag了 递归下去 但sqlBuffer字符串一直是同一个 isDynamic = ParseDynamicTags(child, tag, sqlBuffer, isDynamic, tag.Handler.IsPostParseRequired, statement); } } } } return isDynamic; }
internal void ApplyIteratePropertyReferenceHandling(SqlTagContext ctx, SqlText sqlText) { if (ctx == null) throw new ArgumentNullException("ctx"); if (sqlText == null) throw new ArgumentNullException("sqlText"); if (_propertyPlaceholder != null) { var parsedPropertyName = ReflectionMapper.GetReflectedFullName(ctx, sqlText, this._propertyPlaceholder); this._currentPropertyName = parsedPropertyName; } }
/// <summary> /// Parse Inline ParameterMap /// 对statement insert update delete select 语句的参数进行分析 /// </summary> /// <param name="dataExchangeFactory">The data exchange factory.</param> /// <param name="statementId">The statement id.</param> /// <param name="statement">The statement.</param> /// <param name="sqlStatement">The SQL statement.</param> /// <returns>A new sql command text.</returns> public static SqlText ParseInlineParameterMap(DataExchangeFactory dataExchangeFactory, string statementId, IStatement statement, string sqlStatement) { string newSql = sqlStatement;//赋值得到一条SQL部分语句 List<ParameterProperty> mappingList = new List<ParameterProperty>(); Type parameterClassType = null; if (statement != null) { parameterClassType = statement.ParameterClass;//当前节点属性中的参数类 会不会有多个参数类的情况??? } if (sqlStatement.Contains(NEW_BEGIN_TOKEN))//如果SQL语句包含"@{" { // V3 parameter syntax //@{propertyName,column=string,type=string,dbype=string,direction=[Input/Output/InputOutput],nullValue=string,handler=string} /*以@{开头的例子 <procedure id="InsertAccountViaSPWithDynamicParameter" parameterClass="Account" > ps_InsertAccountWithDefault @{Id,column=Account_ID}//每一个@对应一个ParameterProperty类 ,@{FirstName,column=Account_FirstName} ,@{LastName,column=Account_LastName} ,@{EmailAddress,column=Account_Email,[email protected]} <isNotNull property="NullBannerOption"> ,@{NullBannerOption,column=Account_Banner_Option,dbType=Varchar,type=bool} </isNotNull> @{CartOption,column=Account_Cart_Option,handler=HundredsBool} </procedure> */ if (newSql != null) { string toAnalyse = newSql; int start = toAnalyse.IndexOf(NEW_BEGIN_TOKEN);//@{的下标 int end = toAnalyse.IndexOf(NEW_END_TOKEN);//"}"的下标 StringBuilder newSqlBuffer = new StringBuilder(); while (start > -1 && end > start) { //将语句以 @{ ****** }拆分成3份字符串 string prepend = toAnalyse.Substring(0, start);//@{部分 string append = toAnalyse.Substring(end + NEW_END_TOKEN.Length);//}.....部分 //EmailAddress,column=string,type=string,dbType=Varchar,[email protected] string parameter = toAnalyse.Substring(start + NEW_BEGIN_TOKEN.Length, end - start - NEW_BEGIN_TOKEN.Length);//第一个中间内容部分 ParameterProperty mapping = NewParseMapping(parameter, parameterClassType, dataExchangeFactory, statementId); mappingList.Add(mapping);//将解析后得到的ParameterProperty放入列表中 newSqlBuffer.Append(prepend);//将”@{"加入 或者是 "},@{"部分加入 newSqlBuffer.Append(MARK_TOKEN);//加入 "?"标志 //可能有多个部分 所以循环处理准备 toAnalyse = append; start = toAnalyse.IndexOf(NEW_BEGIN_TOKEN); end = toAnalyse.IndexOf(NEW_END_TOKEN); } /*while 循环完成后的形势是 * ps_InsertAccountWithDefault * @{?},@{?}的大概格式 保存到newSql中 */ newSqlBuffer.Append(toAnalyse); newSql = newSqlBuffer.ToString(); } } else { #region old syntax /* <insert id="InsertAccountViaInlineParameters" parameterClass="Account" > insert into Accounts (Account_ID, Account_FirstName, Account_LastName, Account_Email) values (#Id#, #FirstName#, #LastName#, #EmailAddress:VarChar:[email protected]#) </insert> */ //每# #之间就是一个ParameterProperty类 StringTokenizer parser = new StringTokenizer(sqlStatement, PARAMETER_TOKEN, true);//"#"区分 true表示 如果有#则返回 StringBuilder newSqlBuffer = new StringBuilder(); string token = null; string lastToken = null; IEnumerator enumerator = parser.GetEnumerator(); while (enumerator.MoveNext())//获取当前符号到下一符号之间的字符串 { token = (string)enumerator.Current;//Current真正保存了获取当前符号到下一符号之间的字符串 或 # if (PARAMETER_TOKEN.Equals(lastToken)) //如果上一次是# { // Double token ## = # //先处理# if (PARAMETER_TOKEN.Equals(token)) //如果当前也是# { newSqlBuffer.Append(PARAMETER_TOKEN); token = null; } else //如果当前不是# 也即是两个#之间的字符串 { ParameterProperty mapping = null; //判断# #之间的内容是否含有“:” if (token.IndexOf(PARAM_DELIM) > -1) //如果字符串中含有”:"符号 则进入该函数 { mapping = OldParseMapping(token, parameterClassType, dataExchangeFactory); } else //不含有":",则再次默认","为分隔符 { mapping = NewParseMapping(token, parameterClassType, dataExchangeFactory, statementId); } mappingList.Add(mapping); newSqlBuffer.Append(MARK_TOKEN + " ");//添加"?"作为标志符号 enumerator.MoveNext(); token = (string)enumerator.Current; if (!PARAMETER_TOKEN.Equals(token)) { throw new DataMapperException("Unterminated inline parameter in mapped statement (" + statementId + ")."); } token = null; } } else { if (!PARAMETER_TOKEN.Equals(token)) { newSqlBuffer.Append(token); } } lastToken = token; } /*处理后的sql语句格式应该为 insert into Accounts (Account_ID, Account_FirstName, Account_LastName, Account_Email) values (?, ?, ?, ?) *?对应的参数保存在 mappingList中 *将这两部分 放到SqlText类中 */ newSql = newSqlBuffer.ToString(); #endregion } //将List内容转化为数组的形式 ParameterProperty[] mappingArray = mappingList.ToArray(); //将处理后的简化SQL语句 和 参数列表 保存到 SqlText中 SqlText sqlText = new SqlText(); sqlText.Text = newSql; sqlText.Parameters = mappingArray; return sqlText; }
/// <summary> /// Processes the body children. /// 最终的处理的语句结果在buffer中,也即ctx中的StringBuilder,处理的参数结果在ctx中的ArrayList中 /// </summary> /// <param name="request">The request.</param> /// <param name="ctx">The CTX.</param> /// <param name="parameterObject">The parameter object.</param> /// <param name="childEnumerator">The child enumerator.</param> /// <param name="buffer">The buffer.</param> private void ProcessBodyChildren( RequestScope request, SqlTagContext ctx, object parameterObject, IEnumerator <ISqlChild> childEnumerator, StringBuilder buffer) { while (childEnumerator.MoveNext()) { ISqlChild child = childEnumerator.Current; if (child is SqlText) { SqlText sqlText = (SqlText)child; string sqlStatement = sqlText.Text; if (sqlText.IsWhiteSpace) { buffer.Append(sqlStatement); } else { // if (SimpleDynamicSql.IsSimpleDynamicSql(sqlStatement)) // { // sqlStatement = new SimpleDynamicSql(sqlStatement, _statement).GetSql(parameterObject); // SqlText newSqlText = _paramParser.ParseInlineParameterMap( null, sqlStatement ); // sqlStatement = newSqlText.Text; // ParameterProperty[] mappings = newSqlText.Parameters; // if (mappings != null) // { // for (int i = 0; i < mappings.Length; i++) // { // ctx.AddParameterMapping(mappings[i]); // } // } // } // BODY OUT buffer.Append(" "); buffer.Append(sqlStatement); //添加当前的SQL语句 //处理参数列表 ParameterProperty[] parameters = sqlText.Parameters; if (parameters != null) { int length = parameters.Length; for (int i = 0; i < length; i++) { ctx.AddParameterMapping(parameters[i]); } } } } else if (child is SqlTag) { SqlTag tag = (SqlTag)child; ISqlTagHandler handler = tag.Handler;//此处是DynamicTagHandler处理类 int response = BaseTagHandler.INCLUDE_BODY; do { StringBuilder body = new StringBuilder(); //返回INCLUDE_BODY,即1 此处为处理开头的情况准备 response = handler.DoStartFragment(ctx, tag, parameterObject); if (response != BaseTagHandler.SKIP_BODY) { if (ctx.IsOverridePrepend && ctx.FirstNonDynamicTagWithPrepend == null && tag.IsPrependAvailable && !(tag.Handler is DynamicTagHandler)) { //此处应该是判断第一个查询条件时的开头问题 ctx.FirstNonDynamicTagWithPrepend = tag; } //递归调用,当前SqlTag中处理后的SQL语句保存到了临时的body中 后面再加入到buffer中 ProcessBodyChildren(request, ctx, parameterObject, tag.GetChildrenEnumerator(), body); //处理结尾的片段部分 返回INCLUDE_BODY,1 response = handler.DoEndFragment(ctx, tag, parameterObject, body); //处理prepend属性节点的问题 handler.DoPrepend(ctx, tag, parameterObject, body); if (response != BaseTagHandler.SKIP_BODY) { if (body.Length > 0) { // BODY OUT if (handler.IsPostParseRequired) { //将body中的SQL语句分析参数和SQL语句到SqlText中 SqlText sqlText = InlineParameterMapParser.ParseInlineParameterMap(dataExchangeFactory, statement.Id, null, body.ToString()); buffer.Append(sqlText.Text); ParameterProperty[] mappings = sqlText.Parameters; if (mappings != null) { int length = mappings.Length; for (int i = 0; i < length; i++) { ctx.AddParameterMapping(mappings[i]); } } } else { buffer.Append(" "); buffer.Append(body.ToString()); } //此处是判断SQL语句查询条件时的关键字开头问题 if (tag.IsPrependAvailable && tag == ctx.FirstNonDynamicTagWithPrepend) { ctx.IsOverridePrepend = false; } } } } }while (response == BaseTagHandler.REPEAT_BODY); } } }
/// <summary> /// Parse dynamic tags /// </summary> /// <param name="statementConfig">The statement config.</param> /// <param name="dynamic">The dynamic.</param> /// <param name="sqlBuffer">The SQL buffer.</param> /// <param name="isDynamic">if set to <c>true</c> [is dynamic].</param> /// <param name="postParseRequired">if set to <c>true</c> [post parse required].</param> /// <param name="statement">The statement.</param> /// <returns></returns> private bool ParseDynamicTags( IConfiguration statementConfig, IDynamicParent dynamic, StringBuilder sqlBuffer, bool isDynamic, bool postParseRequired, IStatement statement) { ConfigurationCollection children = statementConfig.Children; int count = children.Count; for (int i = 0; i < count; i++) { IConfiguration child = children[i]; if (child.Type == ConfigConstants.ELEMENT_TEXT || child.Type == ConfigConstants.ELEMENT_CDATA) { string childValueString = child.Value; if (statement.PreserveWhitespace) { childValueString = childValueString .Replace('\n', ' ') .Replace('\r', ' ') .Replace('\t', ' ') .Trim(); } SqlText sqlText = null; if (postParseRequired) { sqlText = new SqlText(); sqlText.Text = childValueString; } else { sqlText = InlineParameterMapParser.ParseInlineParameterMap(modelStore.DataExchangeFactory, statementConfig.Id, null, childValueString); } dynamic.AddChild(sqlText); sqlBuffer.Append(" " + childValueString); } else if (child.Type == ConfigConstants.ELEMENT_SELECTKEY || child.Type == ConfigConstants.ELEMENT_INCLUDE) { } else { IDeSerializer serializer = deSerializerFactory.GetDeSerializer(child.Type); if (serializer != null) { isDynamic = true; SqlTag tag; tag = serializer.Deserialize(child); dynamic.AddChild(tag); if (child.Children.Count > 0) { isDynamic = ParseDynamicTags(child, tag, sqlBuffer, isDynamic, tag.Handler.IsPostParseRequired, statement); } } } } return isDynamic; }