<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      重寫ExpressionVisitor完成LINQ查詢Where運算符表達式樹解析生成Sql腳本(Oracle版本)

      眾所周知,ORM是一種為了解決面向?qū)ο缶幊膛c關(guān)系數(shù)據(jù)庫存在的互不匹配的現(xiàn)象的技術(shù),其目標是基于面向?qū)ο缶幊陶Z言(如C#、Java等)持久化類及映射關(guān)系完成對數(shù)據(jù)庫操作(一般為讀操作與寫操作,也就是常說的增刪改查)。其中一個關(guān)鍵點則是如何生成關(guān)系數(shù)據(jù)庫能夠識別的Sql,此處只討論C#ORM實現(xiàn)中讀操作生成Sql,也就是如何完成C#中LINQ查詢到Sql的轉(zhuǎn)換。LINQ中定義了大量大查詢操作符,而基于數(shù)據(jù)庫查詢一般都需要使用Where子句,故在此我們進一步縮小討論范圍至LINQ的Where操作符。

      針對某一持久化類T,執(zhí)行Where查詢的入?yún)⒖捎?code>Func<T,bool>表示,也就是我們需要基于入?yún)?code>Func<T,bool>生成對應查詢Sql語句。但基于以下兩點:

      • Func<T,bool>解析較為復雜,而.NET Framework中LINQ查詢涉及的各自操作對應的表達式樹被較為完整的定義,可通過重寫ExpressionVisitor實現(xiàn)解析轉(zhuǎn)換生成查詢Sql;
      • .Where函數(shù)可接收Func<T,bool>Expression<Func<T,bool>>入?yún)ⅲ唧w取決于數(shù)據(jù)源為IEnumerable<T>還是IQueryable<T>,考慮數(shù)據(jù)集成查詢定義接口為IQueryable<T>及后期兼容性,故將解析入?yún)⒃O(shè)置為表達式樹。

      我們調(diào)整入?yún)?code>Expression<Func<T,bool>>,完成將其轉(zhuǎn)換為對應Sql查詢語句。

      映射關(guān)系

      基于自定義Attribute作用于持久化類屬性或持久化類建立面向?qū)ο缶幊陶Z言至關(guān)系型數(shù)據(jù)庫的映射關(guān)系
      • 持久化類字段或?qū)傩杂成渲翑?shù)據(jù)庫字段,包括字段名、數(shù)據(jù)類型、是否可空、是否主鍵、默認值、字段備注等內(nèi)容。
      using System;
      
      namespace FXY.Code.ORM.Mapping
      {
      
          public class DbColumnMappingAttribute : Attribute
          {
              public string ProtertyName;
              public string ColumnName;
              public string DataType;
              //public bool AllowNull;
              //public bool IsKey;
              //public string DefaultValue;
              //public string DeafultFuncValue;
          }
      }
      
      • 持久化類映射至數(shù)據(jù)庫表,包括數(shù)據(jù)庫名(用戶名)、表名、表備注、字段映射集合(表包含多個字段)等
      using System;
      using System.Collections.Generic;
      
      namespace FXY.Code.ORM.Mapping
      {
          public class DbTableMappingAttribute : Attribute
          {
              public string EntityName;
              public string TableName;
              public string TableDescribtion;
              public string DataBaseName;
              public List<DbColumnMappingAttribute> DbColumns;
      
              public Type EntityType;
          }
      }
      
      基于持久化類獲取數(shù)據(jù)庫映射結(jié)果接口定義與默認實現(xiàn)
      • 接口定義
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      using System.Reflection;
      
      namespace FXY.Code.ORM.Mapping
      {
          public interface IDataBaseMapping
          {
              /// <summary>
              /// 獲取數(shù)據(jù)庫名稱
              /// </summary>
              /// <typeparam name="TSource"></typeparam>
              /// <returns></returns>
              string GetDbName<TSource>();
      
              /// <summary>
              /// 獲取數(shù)據(jù)庫名稱
              /// </summary>
              /// <param name="type"></param>
              /// <returns></returns>
              string GetDbName(Type type);
      
              /// <summary>
              /// 獲取數(shù)據(jù)庫表名
              /// </summary>
              /// <typeparam name="TSource"></typeparam>
              /// <returns></returns>
              string GetDbTableName<TSource>();
      
              /// <summary>
              /// 獲取數(shù)據(jù)庫表名
              /// </summary>
              /// <typeparam name="type"></typeparam>
              /// <returns></returns>
              string GetDbTableName(Type type);
      
              /// <summary>
              /// 獲取數(shù)據(jù)庫字段名
              /// </summary>
              /// <param name="memberInfo"></param>
              /// <returns></returns>
              string GetColumnName(MemberInfo memberInfo);
          }
      }
      
      

      觀察接口定義入?yún)⒓昂罄m(xù)默認實現(xiàn)可發(fā)現(xiàn):入?yún)⒕鶠?code>System.Reflection命名空間下類,故獲取數(shù)據(jù)庫映射結(jié)果涉及運行時反射使用,存在一定程度的性能損失;
      該處只考慮實現(xiàn),暫不考慮性能,可以考慮將映射規(guī)則持久化(推薦使用XML或JSON等格式,且為文件格式保存,能夠?qū)崿F(xiàn)快速加載;不建議使用數(shù)據(jù)庫存儲,依賴度太高且讀取耗時長)及修改或自定義實現(xiàn)IDataBaseMapping替換默認實現(xiàn)DataBaseMapping,避免運行時反射調(diào)用的性能損失。

      • 默認實現(xiàn)
      using System;
      using System.Data.Linq.Mapping;
      using System.Reflection;
      
      namespace FXY.Code.ORM.Mapping
      {
          /// <summary>
          /// 數(shù)據(jù)庫與實體映射類
          /// </summary>
          public class DataBaseMapping : IDataBaseMapping
          {
              /// <summary>
              /// 獲取數(shù)據(jù)庫名稱
              /// </summary>
              /// <typeparam name="TSource"></typeparam>
              /// <returns></returns>
              public virtual string GetDbName<TSource>()
              {
                  return string.Empty;
              }
      
              /// <summary>
              /// 獲取數(shù)據(jù)庫表名
              /// </summary>
              /// <typeparam name="TSource"></typeparam>
              /// <returns></returns>
              public virtual string GetDbTableName<TSource>()
              {
                  return GetDbTableName(typeof(TSource));
              }
      
              /// <summary>
              /// 獲取數(shù)據(jù)庫字段名
              /// </summary>
              /// <param name="memberInfo"></param>
              /// <returns></returns>
              public virtual string GetColumnName(MemberInfo memberInfo)
              {
                  var columnAttribute = memberInfo.GetAttribute<DbColumnMappingAttribute>();
                  return (columnAttribute?.ColumnName ?? memberInfo.Name).ToUpper();
              }
      
              public string GetDbName(Type type)
              {
                  var tableAttribute = type.GetAttribute<DbTableMappingAttribute>();
                  if (tableAttribute == null)
                  {
                      throw new NotSupportedException("實體尚未設(shè)置DbTableMappingAttribute特性,請先設(shè)置或重寫該方法。");
                  }
                  else
                  {
                      return tableAttribute.DataBaseName.ToUpper();
                  }
              }
      
              public string GetDbTableName(Type type)
              {
                  var tableAttribute = type.GetAttribute<DbTableMappingAttribute>();
                  if (tableAttribute == null)
                  {
                      throw new NotSupportedException("實體尚未設(shè)置DbTableMappingAttribute特性,請先設(shè)置或重寫該方法。");
                  }
                  else
                  {
                      return tableAttribute.TableName.ToUpper();
                  }
              }
          }
      }
      
      
      擴展類,查看源碼
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Reflection;
      using System.Text;
      
      namespace FXY.Code.ORM.Mapping
      {
          public static class MappingExpression
          {
              public static object GetValue(this PropertyInfo propertyInfo, object obj)
              {
                  return propertyInfo.GetValue(obj, null);
              }
      
              public static TAttribute GetAttribute<TAttribute>(this MemberInfo memberInfo)
                  where TAttribute : Attribute
              {
                  var attributes = memberInfo.GetCustomAttributes(typeof(TAttribute), true);
                  if (attributes != null && attributes.Length > 0)
                  {
                      return attributes[0] as TAttribute;
                  }
      
                  return null;
              }
      
              public static TAttribute GetAttribute<TAttribute>(this Type type)
                  where TAttribute : Attribute
              {
                  var attributes = type.GetCustomAttributes(typeof(TAttribute), true);
                  TAttribute attribute = attributes != null && attributes.Length > 0 ? attributes[0] as TAttribute : null;
                  return attribute;
              }
      
              public static void Add(this StringBuilder sb, string str)
              {
      
              }
      
              public static IEnumerable<T> LastSkip<T>(this IEnumerable<T> equatable, int count)
              {
                  return equatable.Take(equatable.Count() - count);
              }
      
              public static string RemoveFirstAndLastChar(this string str, char skip = '\'')
              {
                  var list = str as IEnumerable<char>;
                  if (list?.FirstOrDefault() == skip)
                  {
                      list = list.Skip(1);
                  }
                  if (list?.LastOrDefault() == skip)
                  {
                      list = list.LastSkip(1);
                  }
                  return new string(list.ToArray());
              }
          }
      }
      
      

      表達式樹解析

      using FXY.Code.ORM.Mapping;
      using System;
      using System.Collections.Generic;
      using System.Data.Linq.Mapping;
      using System.Linq;
      using System.Linq.Expressions;
      using System.Reflection;
      using System.Text.RegularExpressions;
      
      namespace FXY.Code.ORM.ExpressionVisit
      {
          public class WhereExpressionVisitor : ExpressionVisitor
          {
              /// <summary>
              /// 是否啟用數(shù)據(jù)庫字段與實體屬性之間的映射關(guān)系。
              /// </summary>
              private bool useColumnAttributeMap;
      
              /// <summary>
              /// 是否啟用參數(shù)化
              /// </summary>
              private bool useDbParamter;
      
              /// <summary>
              /// 是否生成完整的查詢語句
              /// </summary>
              private bool generateFullQuery;
      
              /// <summary>
              /// 參數(shù)化字典
              /// </summary>
              private Dictionary<string, object> dbParameters = new Dictionary<string, object>();
      
              /// <summary>
              /// 參數(shù)化關(guān)鍵字,如oracle為":Id"格式
              /// </summary>
              private string dbParamterKey = "";
      
              /// <summary>
              /// 是否啟用表別名
              /// </summary>
              private bool useAlias;
      
              private IDataBaseMapping dataBaseMapper;
      
              /// <summary>
              /// 構(gòu)造函數(shù)
              /// </summary>
              /// <param name="useColumnAttributeMap">是否啟用<see cref="DbColumnMappingAttribute"/>特性建立屬性與數(shù)據(jù)庫字段之間的映射關(guān)系。</param>
              /// <param name="generateFullQuery">是否生成完成的數(shù)據(jù)庫查詢語句,false不會返回SELECT * FROM {TABLE} WHERE部分。</param>
              /// <param name="useDbParamter">是否啟用參數(shù)化</param>
              /// <param name="dbParamterKey">參數(shù)化</param>
              public WhereExpressionVisitor(bool useColumnAttributeMap,
                  bool generateFullQuery,
                  bool useDbParamter,
                  string dbParamterKey,
                  bool useAlias,
                  IDataBaseMapping dataBaseMapping = null)
              {
                  this.useColumnAttributeMap = useColumnAttributeMap;
                  this.generateFullQuery = generateFullQuery;
                  this.useDbParamter = useDbParamter;
                  this.dbParamterKey = dbParamterKey;
                  this.useAlias = useAlias;
      
                  this.dataBaseMapper = dataBaseMapping ?? new DataBaseMapping();
              }
      
              /// 構(gòu)造函數(shù)
              /// </summary>
              public WhereExpressionVisitor()
                 : base()
              {
              }
      
              public void SetDataBaseMapper<T>() where T : DataBaseMapping, new()
              {
                  this.dataBaseMapper = new T();
              }
      
              /// <summary>
              /// 獲取參數(shù)化字典
              /// </summary>
              /// <returns></returns>
              public Dictionary<string, object> GetDbParamter() => dbParameters;
      
              /// <summary>
              /// 將表達式樹解析為數(shù)據(jù)查詢語句
              /// </summary>
              /// <typeparam name="TSource">實體</typeparam>
              /// <param name="expression">表達式樹</param>
              /// <returns></returns>
              public string ToSql<TSource>(Expression<Func<TSource, bool>> expression)
              {
                  string result = "";
                  dbParameters.Clear();
                  if (generateFullQuery)
                  {
                      string dbName = dataBaseMapper.GetDbName<TSource>();
                      string tableName = dataBaseMapper.GetDbTableName<TSource>();
                      if (!string.IsNullOrWhiteSpace(dbName))
                      {
                          tableName = $"{dbName}.{tableName}";
                      };
      
                      result += $@"SELECT * FROM {tableName}";
                      if (useAlias)
                      {
                          LambdaExpression lambdaExpression = expression;
                          string tableParamterName = lambdaExpression.Parameters[0].Name;
                          result += $@" {tableParamterName}";
                      }
                      result += $@" WHERE ";
                  }
                  result += Visit(expression.Body);
                  return result;
              }
      
              public new string Visit(Expression node)
              {
                  if (node is BinaryExpression binaryExpression)
                  {
                      return VisitBinary(binaryExpression);
                  }
                  else if (node is ConditionalExpression conditionalExpression)
                  {
                      return VisitConditional(conditionalExpression);
                  }
                  else if (node is ConstantExpression constantExpression)
                  {
                      return VisitConstant(constantExpression);
                  }
                  else if (node is MemberExpression memberExpression)
                  {
                      return VisitMember(memberExpression);
                  }
                  else if (node is ParameterExpression parameterExpression)
                  {
                      return VisitParameter(parameterExpression);
                  }
                  else if (node is MethodCallExpression methodCallExpression)
                  {
                      return VisitMethodCall(methodCallExpression);
                  }
                  else if (node is UnaryExpression unaryExpression)
                  {
                      return VisitUnary(unaryExpression);
                  }
                  else if (node is NewExpression newExpression)
                  {
                      return VisitNew(newExpression);
                  }
      
                  throw new NotSupportedException();
              }
      
              protected new string VisitBinary(BinaryExpression node)
              {
                  if (node == null)
                  {
                      return string.Empty;
                  }
      
                  switch (node.NodeType)
                  {
                      /*條件布爾運算*/
                      case ExpressionType.AndAlso: return $"({Visit(node.Left)}) AND ({Visit(node.Right)})";
                      case ExpressionType.OrElse: return $"({Visit(node.Left)}) OR ({Visit(node.Right)})";
      
                      /*比較運算*/
                      case ExpressionType.GreaterThan: return $"{Visit(node.Left)}>{Visit(node.Right)}";
                      case ExpressionType.GreaterThanOrEqual: return $"{Visit(node.Left)}>={Visit(node.Right)}";
                      case ExpressionType.Equal: return $"{Visit(node.Left)}={Visit(node.Right)}";
                      case ExpressionType.NotEqual: return $"{Visit(node.Left)}<>{Visit(node.Right)}";
                      case ExpressionType.LessThan: return $"{Visit(node.Left)}<{Visit(node.Right)}";
                      case ExpressionType.LessThanOrEqual: return $"{Visit(node.Left)}<={Visit(node.Right)}";
      
                      /*算術(shù)運算*/
                      case ExpressionType.Add: return Visit(Expression.Call(node.Method, node.Left, node.Right));
                      case ExpressionType.AddChecked: return Visit(Expression.Call(node.Method, node.Left, node.Right));
                      case ExpressionType.Divide: return Visit(Expression.Call(node.Method, node.Left, node.Right));
                      case ExpressionType.Modulo: return Visit(Expression.Call(node.Method, node.Left, node.Right));
                      case ExpressionType.Multiply: return Visit(Expression.Call(node.Method, node.Left, node.Right));
                      case ExpressionType.MultiplyChecked: return Visit(Expression.Call(node.Method, node.Left, node.Right));
                      case ExpressionType.Subtract: return Visit(Expression.Call(node.Method, node.Left, node.Right));
                      case ExpressionType.SubtractChecked: return Visit(Expression.Call(node.Method, node.Left, node.Right));
      
                      ///*移位運算*/
                      //case ExpressionType.LeftShift:
                      //case ExpressionType.RightShift:
      
                      /*合并運算*/
                      case ExpressionType.Coalesce: return $" NVL({Visit(node.Left)},{Visit(node.Right)})";
      
                      ///*數(shù)組索引操作*/
                      //case ExpressionType.ArrayIndex:
      
                      default: throw new NotSupportedException($"二元表達式樹節(jié)點類型[{node.NodeType}]暫不支持解析。");
                  }
              }
      
              protected new string VisitConditional(ConditionalExpression node)
              {
                  if (node.Test is BinaryExpression b)
                  {
                      return $" (CASE {Visit(b.Left)} WHEN {Visit(b.Right)} THEN {Visit(node.IfTrue)} ELSE {Visit(node.IfFalse)} END)";
                  }
                  throw new NotSupportedException();
              }
              protected new string VisitConstant(ConstantExpression node)
              {
                  if (node == null
                      || node.Value == null)
                  {
                      throw new NotSupportedException($"常量表達式樹解析失敗,不允許為空。");
                  }
      
                  Type type = node.Value.GetType();
                  string result = "";
      
                  if (type == typeof(string)
                      || type == typeof(char))
                  {
                      result = $"'{node.Value}'";
                  }
                  else if (type == typeof(short)
                      || type == typeof(int)
                      || type == typeof(long)
                      || type == typeof(float)
                      || type == typeof(double)
                      || type == typeof(decimal))
                  {
                      result = $"{node.Value}";
                  }
                  else if (type == typeof(DateTime))
                  {
                      DateTime.TryParse(node.Value.ToString(), out DateTime datetime);
                      result = $"TO_DATE('{datetime.ToString("yyyy-MM-dd HH:mm:ss")}','yyyy-MM-dd hh24:mi:ss')";
                  }
                  else
                  {
                      throw new NotSupportedException($"暫不支持[{type.FullName}]常量類型的解析。");
                  }
      
                  if (useDbParamter)
                  {
                      string paramName = $"{dbParamterKey}Param{dbParameters.Count}";
                      object paramValue = result;
                      dbParameters.Add(paramName, paramValue);
                      result = paramName;
                  }
      
                  return result;
              }
      
              protected new string VisitMember(MemberExpression node)
              {
                  if (node == null)
                  {
                      return string.Empty;
                  }
      
                  if (node.Expression is ConstantExpression constantExpression)
                  {
                      object value = null;
                      if (node.Member is PropertyInfo propertyInfo)
                      {
                          value = propertyInfo.GetValue(constantExpression.Value);
                      }
                      if (node.Member is FieldInfo fieldInfo)
                      {
                          value = fieldInfo.GetValue(constantExpression.Value);
                      }
      
                      return Visit(Expression.Constant(value));
                  }
      
                  if (node.Expression is ParameterExpression parameterExpression)
                  {
                      string result = "";
                      if (useAlias)
                      {
                          result += $"{Visit(parameterExpression)}.";
                      }
                      string columnName = !useColumnAttributeMap
                          ? node.Member.Name
                          : dataBaseMapper.GetColumnName(node.Member);
                      result += $"{columnName.ToUpper()}";
                      return result;
                  }
      
                  throw new NotSupportedException($"暫不支持[{node.Expression.ToString()}]MemberExpression的解析。");
              }
      
              protected new string VisitMethodCall(MethodCallExpression node)
              {
                  switch (node.Method.ReturnType.Name)
                  {
                      case "Boolean": return VisitMethodCallReturnBoolean(node);
                      case "String": return VisitMethodCallReturnString(node);
                      default: return "";
                  }
      
              }
      
              protected new string VisitParameter(ParameterExpression node)
              {
                  return useAlias ? $"{node.Name}" : string.Empty;
              }
      
              protected new string VisitUnary(UnaryExpression node)
              {
                  return Visit(node.Operand);
              }
      
              protected new string VisitNew(NewExpression node)
              {
                  if (node.Type == typeof(DateTime))
                  {
                      int hour = 0;
                      int minute = 0;
                      int second = 0;
                      int.TryParse(node.Arguments[0].ToString(), out int year);
                      int.TryParse(node.Arguments[1].ToString(), out int month);
                      int.TryParse(node.Arguments[2].ToString(), out int day);
                      if (node.Arguments.Count > 3)
                      {
                          int.TryParse(node.Arguments[3].ToString(), out hour);
                          int.TryParse(node.Arguments[4].ToString(), out minute);
                          int.TryParse(node.Arguments[5].ToString(), out second);
                      }
                      DateTime dateTime = new DateTime(year, month, day, hour, minute, second);
                      return $"TO_DATE('{dateTime.ToString("yyyy-MM-dd HH:mm:ss")}','yyyy-MM-dd hh24:mi:ss')";
                  }
      
                  return string.Empty;
              }
      
              protected new string VisitBlock(BlockExpression node) { throw new NotSupportedException(); }
              protected new string VisitDebugInfo(DebugInfoExpression node) { throw new NotSupportedException(); }
              protected new string VisitDefault(DefaultExpression node) { throw new NotSupportedException(); }
              protected new string VisitDynamic(DynamicExpression node) { throw new NotSupportedException(); }
              protected new string VisitExtension(Expression node) { throw new NotSupportedException(); }
              protected new string VisitGoto(GotoExpression node) { throw new NotSupportedException(); }
              protected new string VisitIndex(IndexExpression node) { throw new NotSupportedException(); }
              protected new string VisitInvocation(InvocationExpression node) { throw new NotSupportedException(); }
              protected new string VisitLabel(LabelExpression node) { throw new NotSupportedException(); }
              protected new string VisitLambda<T>(Expression<T> node) { throw new NotSupportedException(); }
              protected new string VisitListInit(ListInitExpression node) { throw new NotSupportedException(); }
              protected new string VisitLoop(LoopExpression node) { throw new NotSupportedException(); }
              protected new string VisitMemberInit(MemberInitExpression node) { throw new NotSupportedException(); }
              protected new string VisitNewArray(NewArrayExpression node) { throw new NotSupportedException(); }
              protected new string VisitRuntimeVariables(RuntimeVariablesExpression node) { throw new NotSupportedException(); }
              protected new string VisitSwitch(SwitchExpression node) { throw new NotSupportedException(); }
              protected new string VisitTry(TryExpression node) { throw new NotSupportedException(); }
              protected new string VisitTypeBinary(TypeBinaryExpression node) { throw new NotSupportedException(); }
      
              #region VisitMethodCall By Return Type
              public virtual string VisitMethodCallReturnBoolean(MethodCallExpression node)
              {
                  switch (node.Method.Name)
                  {
                      case "StartsWith":
                          return $"{Visit(node.Object)} LIKE { string.Join("", Visit(node.Arguments[0]).LastSkip(1))}%'";
                      case "EndsWith":
                          return $"{Visit(node.Object)} LIKE '%{ string.Join("", Visit(node.Arguments[0]).Skip(1).LastSkip(1))}'";
                      case "Equals":
                          return $"{Visit(node.Object)}={string.Join("", Visit(node.Arguments[0]))}";
                      case "Contains":
                          return $"{ Visit(node.Object)} LIKE '%{ string.Join("", Visit(node.Arguments[0]).Skip(1).LastSkip(1))}%'";
      
                      default:
                          return string.Empty;
                  }
              }
      
              public virtual string VisitMethodCallReturnString(MethodCallExpression node)
              {
                  switch (node.Method.Name)
                  {
                      case "Concat":
                          return $"'{string.Join("", node.Arguments.Select(p => Visit(p).RemoveFirstAndLastChar()))}'";
                      case "Format":
                          var array1 = Regex.Split(node.Arguments[0].ToString().Substring(1), "{[0-9]+}");
                          var array2 = node.Arguments.Skip(1).ToList();
                          if (node.Arguments.Count > 1 && node.Arguments[1] is NewArrayExpression newArrayExpression)
                          {
                              array2 = newArrayExpression.Expressions.ToList();
                          }
                          return $@"'{string.Join("",
                              array2.Select(p => array1[array2.IndexOf(p)] + Visit(p).RemoveFirstAndLastChar()))}'";
                      case "ToLower": return $"LOWER({Visit(node.Arguments[0])})";
                      case "ToUpper": return $"UPPER({Visit(node.Arguments[0])})";
                      default: return string.Empty;
                  }
              }
              #endregion
      
          }
      }
      
      擴展輔助類
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Reflection;
      using System.Text;
      
      namespace FXY.Code.ORM.ExpressionVisit
      {
          public static class ExtensionExpression
          {
              public static object GetValue(this PropertyInfo propertyInfo, object obj)
              {
                  return propertyInfo.GetValue(obj, null);
              }
      
              public static TAttribute GetAttribute<TAttribute>(this MemberInfo memberInfo)
                  where TAttribute : Attribute
              {
                  var attributes = memberInfo.GetCustomAttributes(typeof(TAttribute), true);
                  if (attributes != null && attributes.Length > 0)
                  {
                      return attributes[0] as TAttribute;
                  }
      
                  return null;
              }
      
              public static TAttribute GetAttribute<TAttribute>(this Type type)
                  where TAttribute : Attribute
              {
                  var attributes = type.GetCustomAttributes(typeof(TAttribute), true);
                  TAttribute attribute = attributes != null && attributes.Length > 0 ? attributes[0] as TAttribute : null;
                  return attribute;
              }
      
              public static void Add(this StringBuilder sb, string str)
              {
      
              }
      
              public static IEnumerable<T> LastSkip<T>(this IEnumerable<T> equatable, int count)
              {
                  return equatable.Take(equatable.Count() - count);
              }
      
              public static string RemoveFirstAndLastChar(this string str, char skip = '\'')
              {
                  var list = str as IEnumerable<char>;
                  if (list?.FirstOrDefault() == skip)
                  {
                      list = list.Skip(1);
                  }
                  if (list?.LastOrDefault() == skip)
                  {
                      list = list.LastSkip(1);
                  }
                  return new string(list.ToArray());
              }
          }
      }
      

      單元測試類

      單元測試持久化類
      using FXY.Code.ORM.Mapping;
      
      namespace FXY.Code.ORM.Entity
      {
          [DbTableMapping(DataBaseName = "TEST", TableName = "PATIENT_INFO_1")]
          public class PatientInfo1
          {
              [DbColumnMapping(ColumnName = "PATIENT_ID", DataType = "VARCHAR(30)")]
              public string ID { get; set; }
      
              [DbColumnMapping(ColumnName = "PATIENT_NAME", DataType = "VARCHAR(30)")]
              public string Name { get; set; }
          }
      
          //[DbTableMapping(DataBaseName = "TEST", TableName = "PATIENT_INFO_2")]
          //public class PatientInfo2
          //{
          //    [DbColumnMapping(ColumnName = "PATIENT_ID", DataType = "VARCHAR(30)")]
          //    public string ID { get; set; }
      
          //    [DbColumnMapping(ColumnName = "PATIENT_NAME", DataType = "VARCHAR(30)")]
          //    public string Name { get; set; }
      
          //    [DbColumnMapping(ColumnName = "PATIENT_AGE", DataType = "NUMBER(36)")]
              //public int Age { get; set; }
          //}
      
          //[DbTableMapping(DataBaseName = "TEST", TableName = "PATIENT_INFO_3")]
          //public class PatientInfo3
          //{
          //    [DbColumnMapping(ColumnName = "PATIENT_ID", DataType = "VARCHAR(30)")]
          //    public string ID { get; set; }
      
          //    [DbColumnMapping(ColumnName = "PATIENT_NAME", DataType = "VARCHAR(30)")]
          //    public string Name { get; set; }
      
          //    //[DbColumnMapping(ColumnName = "PATIENT_AGE", DataType = "NUMBER(36)")]
          //    //public int Age { get; set; }
          //}
      }
      
      
      基本流程測試

      測試用例中所謂參數(shù),是基于:

      • 是否啟用基于ColumnAttribute特性建立屬性與數(shù)據(jù)庫字段之間映射關(guān)系;
      • 是否生成完成的數(shù)據(jù)庫查詢語句,false不會返回SELECT * FROM {TABLE} WHERE部分;
      • 是否啟用參數(shù)化;
      • 是否啟用表別名;
      SingleParamVisitorUnitTest:單參數(shù)基本流程測試
      using FXY.Code.ORM.ExpressionVisit;
      using Microsoft.VisualStudio.TestTools.UnitTesting;
      using System;
      
      namespace FXY.Code.ORM.ExpressionVisit.Test
      {
          [TestClass]
          public class SingleParamVisitorUnitTest
          {
              private WhereExpressionVisitor visitor = new WhereExpressionVisitor();
      
      
              #region 單參數(shù)測試
              [TestMethod]
              public void BaseUseColumnMap()
              {
                  visitor = new WhereExpressionVisitor(true, false, false, "", false);
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == "20"), "PATIENT_ID='20'");
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(p => p.Age > 20 && p.Sex == 1),
                      "(PATIENT_AGE>20) AND (PATIENT_SEX=1)");
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(p => p.Age > 20
                      && p.Sex == 1
                      && p.TelePhone.StartsWith("135")),
                      "((PATIENT_AGE>20) AND (PATIENT_SEX=1)) AND (PATIENT_TELEPHONE LIKE '135%')");
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(p => p.Age > 20
                      && p.Sex == 1
                      && (p.TelePhone.StartsWith("135") || p.Province.Contains("云南"))),
                      "((PATIENT_AGE>20) AND (PATIENT_SEX=1)) AND ((PATIENT_TELEPHONE LIKE '135%') OR (PATIENT_PROVINCE LIKE '%云南%'))");
              }
      
              [TestMethod]
              public void BaseGenetateFullQuery()
              {
                  visitor = new WhereExpressionVisitor(false, true, false, "", false);
      
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == "20"),
                      "SELECT * FROM PATIENT WHERE ID='20'");
      
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(p => p.Age > 20 && p.Sex == 1),
                      "SELECT * FROM PATIENT WHERE (AGE>20) AND (SEX=1)");
      
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(p => p.Age > 20
                      && p.Sex == 1
                      && p.TelePhone.StartsWith("135")),
                      "SELECT * FROM PATIENT WHERE ((AGE>20) AND (SEX=1)) AND (TELEPHONE LIKE '135%')");
      
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(p => p.Age > 20
                      && p.Sex == 1
                      && (p.TelePhone.StartsWith("135") || p.Province.Contains("云南"))),
                      "SELECT * FROM PATIENT WHERE ((AGE>20) AND (SEX=1)) AND ((TELEPHONE LIKE '135%') OR (PROVINCE LIKE '%云南%'))");
              }
      
              [TestMethod]
              public void BaseUseDbParamter()
              {
                  visitor = new WhereExpressionVisitor(false, false, true, ":", false);
                  {
                      string sql = visitor.ToSql<PatientInfo>(p => p.ID == "20");
                      var dbPramaters = visitor.GetDbParamter();
                      Assert.AreEqual(sql, "ID=:Param0");
                      Assert.IsTrue(dbPramaters != null && dbPramaters.Count == 1 && dbPramaters[":Param0"].ToString() == "'20'");
                  }
                  {
                      //Assert.ThrowsException<NotSupportedException>(() =>
                      //{
                      //    visitor.ToSql<PatientInfo>(p => p.Age > 20
                      //        && p.Sex == 1
                      //        && (p.TelePhone.StartsWith("135") || p.Province.Contains("云南")));
                      //});
      
                      string sql = visitor.ToSql<PatientInfo>(p => p.Age > 20 && p.Sex == 1);
                      var dbPramaters = visitor.GetDbParamter();
                      Assert.AreEqual(sql, "(AGE>:Param0) AND (SEX=:Param1)");
                      Assert.IsTrue(dbPramaters != null
                          && dbPramaters.Count == 2
                          && Convert.ToInt32(dbPramaters[":Param0"].ToString()) == 20
                          && Convert.ToInt32(dbPramaters[":Param1"].ToString()) == 1);
                  }
              }
      
              [TestMethod]
              public void BaseUseAlias()
              {
                  visitor = new WhereExpressionVisitor(false, false, false, "", true);
      
                  /*單條件*/
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.Age > 20), "p.AGE>20");
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.Age >= 20), "p.AGE>=20");
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.Age == 20), "p.AGE=20");
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.Age != 20), "p.AGE<>20");
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.Age < 20), "p.AGE<20");
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.Age <= 20), "p.AGE<=20");
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.TelePhone.StartsWith("135")), "p.TELEPHONE LIKE '135%'");
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.TelePhone.EndsWith("135")), "p.TELEPHONE LIKE '%135'");
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.TelePhone.Contains("135")), "p.TELEPHONE LIKE '%135%'");
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.TelePhone.Equals("w")), "p.TELEPHONE='w'");
      
                  /*多條件*/
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(
                          p => p.Age > 20 && p.Sex == 1),
                      "(p.AGE>20) AND (p.SEX=1)");
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(
                          p => p.Age > 20 && p.Sex == 1 && p.TelePhone.StartsWith("135")),
                      "((p.AGE>20) AND (p.SEX=1)) AND (p.TELEPHONE LIKE '135%')");
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(
                          p => p.Age > 20 && p.Sex == 1 && (p.TelePhone.StartsWith("135") || p.Province.Contains("云南"))),
                      "((p.AGE>20) AND (p.SEX=1)) AND ((p.TELEPHONE LIKE '135%') OR (p.PROVINCE LIKE '%云南%'))");
              }
              #endregion
          }
      }
      
      
      TwoParamVisitorUnitTest:兩參數(shù)流程流程測試
      using FXY.Code.ORM.ExpressionVisit;
      using Microsoft.VisualStudio.TestTools.UnitTesting;
      using System;
      
      namespace FXY.Code.ORM.ExpressionVisit.Test
      {
          [TestClass]
          public class TwoParamVisitorUnitTest
          {
              private WhereExpressionVisitor visitor = new WhereExpressionVisitor();
              #region 兩參數(shù)測試
              [TestMethod]
              public void BaseUseColumnMapAndFullQuery()
              {
                  visitor = new WhereExpressionVisitor(true, true, false, "", false);
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == "20"), "SELECT * FROM PATIENT WHERE PATIENT_ID='20'");
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(p => p.Age > 20 && p.Sex == 1),
                      "SELECT * FROM PATIENT WHERE (PATIENT_AGE>20) AND (PATIENT_SEX=1)");
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(p => p.Age > 20
                      && p.Sex == 1
                      && p.TelePhone.StartsWith("135")),
                      "SELECT * FROM PATIENT WHERE ((PATIENT_AGE>20) AND (PATIENT_SEX=1)) AND (PATIENT_TELEPHONE LIKE '135%')");
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(p => p.Age > 20
                      && p.Sex == 1
                      && (p.TelePhone.StartsWith("135") || p.Province.Contains("云南"))),
                      "SELECT * FROM PATIENT WHERE ((PATIENT_AGE>20) AND (PATIENT_SEX=1)) AND ((PATIENT_TELEPHONE LIKE '135%') OR (PATIENT_PROVINCE LIKE '%云南%'))");
              }
      
              [TestMethod]
              public void BaseUseColumnMapAndDbParamter()
              {
                  visitor = new WhereExpressionVisitor(true, false, true, ":", false);
                  {
                      string sql = visitor.ToSql<PatientInfo>(p => p.ID == "20");
                      var dbPramaters = visitor.GetDbParamter();
                      Assert.AreEqual(sql, "PATIENT_ID=:Param0");
                      Assert.IsTrue(dbPramaters != null && dbPramaters.Count == 1 && dbPramaters[":Param0"].ToString() == "'20'");
                  }
                  {
                      //Assert.ThrowsException<NotSupportedException>(() =>
                      //{
                      //    visitor.ToSql<PatientInfo>(p => p.Age > 20
                      //        && p.Sex == 1
                      //        && (p.TelePhone.StartsWith("135") || p.Province.Contains("云南")));
                      //});
      
                      string sql = visitor.ToSql<PatientInfo>(p => p.Age > 20 && p.Sex == 1);
                      var dbPramaters = visitor.GetDbParamter();
                      Assert.AreEqual(sql, "(PATIENT_AGE>:Param0) AND (PATIENT_SEX=:Param1)");
                      Assert.IsTrue(dbPramaters != null
                          && dbPramaters.Count == 2
                          && Convert.ToInt32(dbPramaters[":Param0"].ToString()) == 20
                          && Convert.ToInt32(dbPramaters[":Param1"].ToString()) == 1);
                  }
              }
      
              [TestMethod]
              public void BaseUseColumnMapAndAlias()
              {
                  visitor = new WhereExpressionVisitor(true, false, false, "", true);
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == "20"), "p.PATIENT_ID='20'");
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(p => p.Age > 20 && p.Sex == 1),
                      "(p.PATIENT_AGE>20) AND (p.PATIENT_SEX=1)");
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(p => p.Age > 20
                      && p.Sex == 1
                      && p.TelePhone.StartsWith("135")),
                      "((p.PATIENT_AGE>20) AND (p.PATIENT_SEX=1)) AND (p.PATIENT_TELEPHONE LIKE '135%')");
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(p => p.Age > 20
                      && p.Sex == 1
                      && (p.TelePhone.StartsWith("135") || p.Province.Contains("云南"))),
                      "((p.PATIENT_AGE>20) AND (p.PATIENT_SEX=1)) AND ((p.PATIENT_TELEPHONE LIKE '135%') OR (p.PATIENT_PROVINCE LIKE '%云南%'))");
              }
      
              [TestMethod]
              public void BaseGenetateFullQueryAndDbParamter()
              {
                  visitor = new WhereExpressionVisitor(false, true, true, ":", false);
                  {
                      string sql = visitor.ToSql<PatientInfo>(p => p.ID == "20");
                      var dbPramaters = visitor.GetDbParamter();
                      Assert.AreEqual(sql, "SELECT * FROM PATIENT WHERE ID=:Param0");
                      Assert.IsTrue(dbPramaters != null && dbPramaters.Count == 1 && dbPramaters[":Param0"].ToString() == "'20'");
                  }
                  {
                      //Assert.ThrowsException<NotSupportedException>(() =>
                      //{
                      //    visitor.ToSql<PatientInfo>(p => p.Age > 20
                      //        && p.Sex == 1
                      //        && (p.TelePhone.StartsWith("135") || p.Province.Contains("云南")));
                      //});
      
                      string sql = visitor.ToSql<PatientInfo>(p => p.Age > 20 && p.Sex == 1);
                      var dbPramaters = visitor.GetDbParamter();
                      Assert.AreEqual(sql, "SELECT * FROM PATIENT WHERE (AGE>:Param0) AND (SEX=:Param1)");
                      Assert.IsTrue(dbPramaters != null
                          && dbPramaters.Count == 2
                          && Convert.ToInt32(dbPramaters[":Param0"].ToString()) == 20
                          && Convert.ToInt32(dbPramaters[":Param1"].ToString()) == 1);
                  }
              }
      
              [TestMethod]
              public void BaseGenetateFullQueryAndUseAlias()
              {
                  visitor = new WhereExpressionVisitor(false, true, false, "", true);
      
                  /*不啟用字段映射,不生成完整查詢語句,不使用參數(shù)化,使用表別名,單條件*/
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.Age > 20), "SELECT * FROM PATIENT p WHERE p.AGE>20");
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.Age >= 20), "SELECT * FROM PATIENT p WHERE p.AGE>=20");
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.Age == 20), "SELECT * FROM PATIENT p WHERE p.AGE=20");
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.Age != 20), "SELECT * FROM PATIENT p WHERE p.AGE<>20");
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.Age < 20), "SELECT * FROM PATIENT p WHERE p.AGE<20");
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.Age <= 20), "SELECT * FROM PATIENT p WHERE p.AGE<=20");
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.TelePhone.StartsWith("135")), "SELECT * FROM PATIENT p WHERE p.TELEPHONE LIKE '135%'");
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.TelePhone.EndsWith("135")), "SELECT * FROM PATIENT p WHERE p.TELEPHONE LIKE '%135'");
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.TelePhone.Contains("135")), "SELECT * FROM PATIENT p WHERE p.TELEPHONE LIKE '%135%'");
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.TelePhone.Equals("w")), "SELECT * FROM PATIENT p WHERE p.TELEPHONE='w'");
      
                  /*不啟用字段映射,不生成完整查詢語句,不使用參數(shù)化,使用表別名,多條件*/
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(
                          p => p.Age > 20 && p.Sex == 1),
                      "SELECT * FROM PATIENT p WHERE (p.AGE>20) AND (p.SEX=1)");
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(
                          p => p.Age > 20 && p.Sex == 1 && p.TelePhone.StartsWith("135")),
                      "SELECT * FROM PATIENT p WHERE ((p.AGE>20) AND (p.SEX=1)) AND (p.TELEPHONE LIKE '135%')");
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(
                          p => p.Age > 20 && p.Sex == 1 && (p.TelePhone.StartsWith("135") || p.Province.Contains("云南"))),
                      "SELECT * FROM PATIENT p WHERE ((p.AGE>20) AND (p.SEX=1)) AND ((p.TELEPHONE LIKE '135%') OR (p.PROVINCE LIKE '%云南%'))");
              }
      
              [TestMethod]
              public void BaseUseDbParamterAndUseAlias()
              {
                  visitor = new WhereExpressionVisitor(false, false, true, ":", true);
                  {
                      string sql = visitor.ToSql<PatientInfo>(p => p.ID == "20");
                      var dbPramaters = visitor.GetDbParamter();
                      Assert.AreEqual(sql, "p.ID=:Param0");
                      Assert.IsTrue(dbPramaters != null && dbPramaters.Count == 1 && dbPramaters[":Param0"].ToString() == "'20'");
                  }
                  {
                      //Assert.ThrowsException<NotSupportedException>(() =>
                      //{
                      //    visitor.ToSql<PatientInfo>(p => p.Age > 20
                      //        && p.Sex == 1
                      //        && (p.TelePhone.StartsWith("135") || p.Province.Contains("云南")));
                      //});
      
                      string sql = visitor.ToSql<PatientInfo>(p => p.Age > 20 && p.Sex == 1);
                      var dbPramaters = visitor.GetDbParamter();
                      Assert.AreEqual(sql, "(p.AGE>:Param0) AND (p.SEX=:Param1)");
                      Assert.IsTrue(dbPramaters != null
                          && dbPramaters.Count == 2
                          && Convert.ToInt32(dbPramaters[":Param0"].ToString()) == 20
                          && Convert.ToInt32(dbPramaters[":Param1"].ToString()) == 1);
                  }
              }
              #endregion
          }
      }
      
      
      ThreeParamVisitorUnitTest:三參數(shù)基本流程測試
      using FXY.Code.ORM.ExpressionVisit;
      using Microsoft.VisualStudio.TestTools.UnitTesting;
      
      namespace FXY.Code.ORM.ExpressionVisit.Test
      {
          [TestClass]
          public class ThreeParamVisitorUnitTest
          {
              private WhereExpressionVisitor visitor = new WhereExpressionVisitor();
      
              #region 三參數(shù)測試
              [TestMethod]
              public void BaseUseColumnMapAndFullQueryAndDbParamter()
              {
                  visitor = new WhereExpressionVisitor(true, true, true, ":", false);
                  string sql = visitor.ToSql<PatientInfo>(p => p.ID == "20");
                  var dbPramaters = visitor.GetDbParamter();
                  Assert.AreEqual(sql, "SELECT * FROM PATIENT WHERE PATIENT_ID=:Param0");
                  Assert.IsTrue(dbPramaters != null && dbPramaters.Count == 1 && dbPramaters[":Param0"].ToString() == "'20'");
              }
      
              [TestMethod]
              public void BaseUseColumnMapAndFullQueryAndAlias()
              {
                  visitor = new WhereExpressionVisitor(true, true, false, "", true);
                  string sql = visitor.ToSql<PatientInfo>(p => p.ID == "20");
                  Assert.AreEqual(sql, "SELECT * FROM PATIENT p WHERE p.PATIENT_ID='20'");
              }
      
              [TestMethod]
              public void BaseUseFullQueryAndDbParamterAndAlias()
              {
                  visitor = new WhereExpressionVisitor(false, true, true, ":", true);
                  string sql = visitor.ToSql<PatientInfo>(p => p.ID == "20");
                  var dbPramaters = visitor.GetDbParamter();
                  Assert.AreEqual(sql, "SELECT * FROM PATIENT p WHERE p.ID=:Param0");
                  Assert.IsTrue(dbPramaters != null && dbPramaters.Count == 1 && dbPramaters[":Param0"].ToString() == "'20'");
              }
      
              [TestMethod]
              public void BaseUseColumnMapAndDbParamterAndAlias()
              {
                  visitor = new WhereExpressionVisitor(true, false, true, ":", true);
                  string sql = visitor.ToSql<PatientInfo>(p => p.ID == "20");
                  var dbPramaters = visitor.GetDbParamter();
                  Assert.AreEqual(sql, "p.PATIENT_ID=:Param0");
                  Assert.IsTrue(dbPramaters != null && dbPramaters.Count == 1 && dbPramaters[":Param0"].ToString() == "'20'");
              }
              #endregion
          }
      }
      
      
      FourParamVisitorUnitTest:四參數(shù)基本流程測試
      using FXY.Code.ORM.ExpressionVisit;
      using Microsoft.VisualStudio.TestTools.UnitTesting;
      
      namespace FXY.Code.ORM.ExpressionVisit.Test
      {
          [TestClass]
          public class FourParamVisitorUnitTest
          {
              private WhereExpressionVisitor visitor = new WhereExpressionVisitor();
      
              #region 四參數(shù)測試
              [TestMethod]
              public void BaseUseColumnMapAndFullQueryAndDbParamterAndAlias()
              {
                  visitor = new WhereExpressionVisitor(true, true, true, ":", true);
                  string sql = visitor.ToSql<PatientInfo>(p => p.ID == "20");
                  var dbPramaters = visitor.GetDbParamter();
                  Assert.AreEqual(sql, "SELECT * FROM PATIENT p WHERE p.PATIENT_ID=:Param0");
                  Assert.IsTrue(dbPramaters != null && dbPramaters.Count == 1 && dbPramaters[":Param0"].ToString() == "'20'");
              }
              #endregion
      
        
      
          }
      }
      
      其他測試
      CoalesceUnitTest:二元空值運算符,格式為:a??b
      using FXY.Code.ORM.ExpressionVisit;
      using Microsoft.VisualStudio.TestTools.UnitTesting;
      
      namespace FXY.Code.ORM.ExpressionVisit.Test
      {
          [TestClass]
          public class CoalesceUnitTest
          {
              private WhereExpressionVisitor visitor = new WhereExpressionVisitor(true, false, false, "", false);
      
              [TestMethod]
              public void CoalesceTest()
              {
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(p => p.City == (p.Province ?? "成都")),
                      "PATIENT_CITY= NVL(PATIENT_PROVINCE,'成都')");
              }
          }
      }
      
      
      ConditionalExpressionUnitTest:三元條件運算符,語法為:條件表達式?表達式1:表達式2
      using FXY.Code.ORM.ExpressionVisit.Test;
      using FXY.Code.ORM.ExpressionVisit;
      using Microsoft.VisualStudio.TestTools.UnitTesting;
      
      namespace FXY.Code.ORM.ExpressionVisit.Test
      {
          [TestClass]
          public class ConditionalExpressionUnitTest
          {
              private WhereExpressionVisitor visitor = new WhereExpressionVisitor(true, false, false, "", false);
              [TestMethod]
              public void BaseTest()
              {
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(p => p.Age == (p.Sex == 1 ? 22 : 20)),
                      "PATIENT_AGE= (CASE PATIENT_SEX WHEN 1 THEN 22 ELSE 20 END)");
      
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(p => p.City == (p.Sex == 1 ? "成都" : "昆明")),
                      "PATIENT_CITY= (CASE PATIENT_SEX WHEN 1 THEN '成都' ELSE '昆明' END)");
              }
      
          }
      }
      
      DateTimeCompareUnitTest:時間比較
      using FXY.Code.ORM.ExpressionVisit;
      using Microsoft.VisualStudio.TestTools.UnitTesting;
      using System;
      
      namespace FXY.Code.ORM.ExpressionVisit.Test
      {
          [TestClass]
          public class DateTimeCompareUnitTest
          {
              private WhereExpressionVisitor visitor = new WhereExpressionVisitor(true, false, false, "", false);
      
      
              [TestMethod]
              public void BaseDatetieCompareByNew1()
              {
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(p => p.Birthday > new DateTime(1900, 01, 01)),
                      "PATIENT_BIRTHDAY>TO_DATE('1900-01-01 00:00:00','yyyy-MM-dd hh24:mi:ss')");
              }
      
      
              [TestMethod]
              public void BaseDatetieCompareByNew2()
              {
      
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(p => p.Birthday > new DateTime(1900, 01, 01, 2, 3, 4)),
                      "PATIENT_BIRTHDAY>TO_DATE('1900-01-01 02:03:04','yyyy-MM-dd hh24:mi:ss')");
              }
      
              [TestMethod]
              public void BaseDatetieCompareByConstant1()
              {
                  DateTime dateTime = new DateTime(1900, 01, 01);
                  Assert.AreEqual(
                      visitor.ToSql<PatientInfo>(p => p.Birthday > dateTime),
                      "PATIENT_BIRTHDAY>TO_DATE('1900-01-01 00:00:00','yyyy-MM-dd hh24:mi:ss')");
              }
      
              [TestMethod]
              public void BaseDatetieCompareByConstant2()
              {
                  DateTime dateTime = new DateTime(1900, 01, 01, 2, 3, 4);
                  Assert.AreEqual(
                     visitor.ToSql<PatientInfo>(p => p.Birthday > dateTime),
                     "PATIENT_BIRTHDAY>TO_DATE('1900-01-01 02:03:04','yyyy-MM-dd hh24:mi:ss')");
              }
      
              [TestMethod]
              public void BaseDateTimeCanNull()
              {
                  DateTime? dateTime = new DateTime(1900, 01, 01, 2, 3, 4);
                  Assert.AreEqual(
                     visitor.ToSql<PatientInfo>(p => p.Birthday > dateTime),
                     "PATIENT_BIRTHDAY>TO_DATE('1900-01-01 02:03:04','yyyy-MM-dd hh24:mi:ss')");
      
                  dateTime = null;
                  Assert.ThrowsException<NotSupportedException>(() =>
                  {
                      Assert.AreEqual(
                         visitor.ToSql<PatientInfo>(p => p.Birthday > dateTime),
                         "PATIENT_BIRTHDAY>TO_DATE('1900-01-01 02:03:04','yyyy-MM-dd hh24:mi:ss')");
                  });
              }
      
          }
      }
      
      
      StringConcatVisitorUnitTest:字符串連接測試
      using FXY.Code.ORM.ExpressionVisit;
      using Microsoft.VisualStudio.TestTools.UnitTesting;
      
      namespace FXY.Code.ORM.ExpressionVisit.Test
      {
          [TestClass]
          public class StringConcatVisitorUnitTest
          {
              private WhereExpressionVisitor visitor = new WhereExpressionVisitor();
      
              [TestMethod]
              public void OneStringConcat()
              {
                  visitor = new WhereExpressionVisitor(true, true, false, "", true);
                  string id = "1";
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == "0_" + id),
                         "SELECT * FROM PATIENT p WHERE p.PATIENT_ID='0_1'");
              }
      
              [TestMethod]
              public void TwoStringConcat()
              {
                  visitor = new WhereExpressionVisitor(true, true, false, "", true);
                  string id1 = "1";
                  string id2 = "2";
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == "0_" + id1 + "_" + id2),
                         "SELECT * FROM PATIENT p WHERE p.PATIENT_ID='0_1_2'");
              }
      
              [TestMethod]
              public void ThreeStringConcat()
              {
                  visitor = new WhereExpressionVisitor(true, true, false, "", true);
                  string id1 = "1";
                  string id2 = "2";
                  string id3 = "3";
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == "0_" + id1 + "_" + id2 + "_" + id3),
                         "SELECT * FROM PATIENT p WHERE p.PATIENT_ID='0_1_2_3'");
              }
      
              [TestMethod]
              public void FourStringConcat()
              {
                  visitor = new WhereExpressionVisitor(true, true, false, "", true);
                  string id1 = "1";
                  string id2 = "2";
                  string id3 = "3";
                  string id4 = "4";
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == "0_" + id1 + "_" + id2 + "_" + id3 + "_" + id4),
                         "SELECT * FROM PATIENT p WHERE p.PATIENT_ID='0_1_2_3_4'");
              }
      
              [TestMethod]
              public void OneObjectConcat()
              {
                  visitor = new WhereExpressionVisitor(true, true, false, "", true);
                  object id = "1";
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == "0_" + id),
                         "SELECT * FROM PATIENT p WHERE p.PATIENT_ID='0_1'");
              }
      
              [TestMethod]
              public void TwoObjectConcat()
              {
                  visitor = new WhereExpressionVisitor(true, true, false, "", true);
                  object id1 = "1";
                  object id2 = "2";
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == "0_" + id1 + "_" + id2),
                         "SELECT * FROM PATIENT p WHERE p.PATIENT_ID='0_1_2'");
              }
      
              [TestMethod]
              public void OneIntConcat()
              {
                  visitor = new WhereExpressionVisitor(true, true, false, "", true);
                  int id = 1;
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == "0_" + id),
                         "SELECT * FROM PATIENT p WHERE p.PATIENT_ID='0_1'");
              }
      
              [TestMethod]
              public void TwoIntConcat()
              {
                  visitor = new WhereExpressionVisitor(true, true, false, "", true);
                  int id1 = 1;
                  int id2 = 2;
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == "0_" + id1 + "_" + id2),
                         "SELECT * FROM PATIENT p WHERE p.PATIENT_ID='0_1_2'");
              }
          }
      }
      
      
      StringFormatVisitorUnitTest:字符串內(nèi)插測試
      using FXY.Code.ORM.ExpressionVisit;
      using Microsoft.VisualStudio.TestTools.UnitTesting;
      
      namespace FXY.Code.ORM.ExpressionVisit.Test
      {
          [TestClass]
          public class StringFormatVisitorUnitTest
          {
              private WhereExpressionVisitor visitor = new WhereExpressionVisitor();
      
              [TestMethod]
              public void ExtensionUseVariableConstant()
              {
                  visitor = new WhereExpressionVisitor(true, true, false, "", true);
                  string id = "1";
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == id),
                         "SELECT * FROM PATIENT p WHERE p.PATIENT_ID='1'");
              }
      
              [TestMethod]
              public void ExtensionStringInterpolation()
              {
                  visitor = new WhereExpressionVisitor(true, true, false, "", true);
                  string id = "1";
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == $"1_{id}"),
                         "SELECT * FROM PATIENT p WHERE p.PATIENT_ID='1_1'");
      
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == $"1_{id}_{id}"),
             "SELECT * FROM PATIENT p WHERE p.PATIENT_ID='1_1_1'");
      
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == $"1_{id}_{id}_{id}"),
             "SELECT * FROM PATIENT p WHERE p.PATIENT_ID='1_1_1_1'");
      
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == $"1_{id}_{id}_{id}_{id}"),
      "SELECT * FROM PATIENT p WHERE p.PATIENT_ID='1_1_1_1_1'");
      
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == $"1_{id}_{id}_{id}_{id}_{id}"),
      "SELECT * FROM PATIENT p WHERE p.PATIENT_ID='1_1_1_1_1_1'");
      
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == $"1_{id}_{id}_{id}_{id}_{id}_{id}"),
      "SELECT * FROM PATIENT p WHERE p.PATIENT_ID='1_1_1_1_1_1_1'");
              }
          }
      }
      
      
      StringJoinVisitorUnitTest:string.Join函數(shù)測試
      using FXY.Code.ORM.ExpressionVisit;
      using Microsoft.VisualStudio.TestTools.UnitTesting;
      using System.Collections.Generic;
      
      namespace FXY.Code.ORM.ExpressionVisit.Test
      {
          [TestClass]
          public class StringJoinVisitorUnitTest
          {
              private WhereExpressionVisitor visitor = new WhereExpressionVisitor();
      
      
              public void StringJoin()
              {
                  visitor = new WhereExpressionVisitor(true, true, false, "", true);
                  var list = new List<string>() { "1", "2", "3" };
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == string.Join(",", list)),
                         "SELECT * FROM PATIENT p WHERE p.PATIENT_ID='1,2,3'");
              }
      
      
              public void IntJoin()
              {
                  visitor = new WhereExpressionVisitor(true, true, false, "", true);
                  var list = new List<int>() { 1, 2, 3 };
                  Assert.AreEqual(visitor.ToSql<PatientInfo>(p => p.ID == string.Join(",", list)),
                         "SELECT * FROM PATIENT p WHERE p.PATIENT_ID='1,2,3'");
              }
          }
      }
      
      

      單元測試結(jié)果

      posted @ 2022-06-26 00:11  付旭洋  閱讀(360)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 中文字幕有码免费视频| 一道本AV免费不卡播放| 国产成人女人在线观看| 久久se精品一区精品二区国产| 天天摸天天碰天天添| 日韩av日韩av在线| 泸溪县| 日韩精品亚洲国产成人av| 男女动态无遮挡动态图| 叶城县| 国产日产亚洲系列av| 国产AV老师黑色丝袜美腿| 永兴县| 强奷白丝美女在线观看| 国产成人乱色伦区| 成年女人片免费视频播放A| 国产精品自拍一二三四区| 国产盗摄xxxx视频xxxx| 中文在线天堂中文在线天堂| 亚洲精品漫画一二三区| 精品国产一区二区三区四区阿崩| 日韩中文字幕有码午夜美女| 久久99久国产精品66| 特黄做受又粗又大又硬老头| 日本道精品一区二区三区| 苍井空一区二区三区在线观看| 国产精品一区在线蜜臀| 亚洲韩国精品无码一区二区三区 | 亚洲 欧洲 自拍 偷拍 首页| 久久精品国产再热青青青| 中文成人无字幕乱码精品区| 国产精品视频中文字幕| 97人妻成人免费视频| 一区二区丝袜美腿视频| 欧美乱妇高清无乱码免费| 亚洲综合精品香蕉久久网| 综1合AV在线播放| 人妻日韩精品中文字幕| 午夜成人精品福利网站在线观看| 天堂V亚洲国产V第一次| 性欧美大战久久久久久久|