博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
轻量级表达式树解析框架Faller
阅读量:6113 次
发布时间:2019-06-21

本文共 22747 字,大约阅读时间需要 75 分钟。

有话说

之前我写了3篇关于表达式树解析的文章

 

这3篇文章更多的是说明一种方法,一种思路,而代码比较少

在发出来之后也有些朋友互加了好友一起讨论

在经过一些时间的修改和优化后,就有了现在这个框架

目前这个框架实现了SqlServer和Oracle的解释

其他数据库1来是不熟2来没时间3来我更希望大家可以使用这个框架自己动手实现一个数据库的解析,非常有意思

特色

  1. 首先是这个框架的名字 : Faller 中译 伐木工,但我喜欢叫他 "砍树人",因为他把"表达式树"这颗大树砍成一片一片的小块然后转化成sql语句
  2. 轻量 : 不仅仅是代码轻量,重新实现对一个新的数据库支持也很轻量,只需要实现ISaw接口,或继承BaseSaw实现少量方法即可
    如 : 
    Where(u => u.Birthday.Day == 1);                   //EXTRACT(DAY FROM a.BIRTHDAY) = 1Where(u => u.Name.Trim() == "");                    //ltrim(rtrim(a.NAME)) = :auto_p0Where(u => string.IsNullOrEmpty(u.Name));      //a.NAME IS NULL OR a.NAME == ''

     

  3. 灵活 : 在轻量的基础上尽量做到了灵活,可以非常方便的解析各种C#的方法

  4. 对 DateTime.Now 的处理 : 
    如 :  Where(u => u.Birthday < DateTime.Now) //可以被解析为 BIRTHDAY < SYSDATE 或 BIRTHDAY < GETDATE() 
  5. 自由的 SqlExpr : 有时候 我们不得不使用Sql来表示某个数据库特有的数据
    如 :  Set<User>(() => new User{ ID = (SqlExpr)"seq_user.nextval"}) //解析后得到 ID = seq_user.nextval 
  6. 使用方便 : 可以非常方便的嵌入到现已有的项目中,主要根据自己项目的需求重新实现ISaw即可

 

使用方式

void Where(string expected, Expression
> expr){ var parse = Faller.Create(expr); //通过LambdaExpression创建Faller对象 var sql = parse.ToWhere(OracleSaw.Instance);//使用特定的ISaw来格式化Sql语句 //parse.Parameters //解析过程中产生的参数 Assert.AreEqual(expected, sql);}

项目结构

  • Faller : 解析框架主要功能类,不可重写,实现 IFaller 接口,主要方法有 public static IFaller Create(LambdaExpression expr)
  • ISaw : 定义一组方法,它支持自定义Sql语句的格式。Faller负责拆解 LambdaExpression ,然后把特定的对象交给ISaw处理返回sql语句 
  • SawDust : 解析结果。当一个方法在Faller中无法被解释时候,Faller会把方法所用到的对象和参数都构造成为SawDust 并交给ISaw处理,SawDust 由DustType Type和Object Value组成
  • DustType : 表示解释结果类型的枚举 ,它的值有 Undefined, Sql, Object, Number, Array, Boolean, DateTime, Binary, String
  • SqlExpr : Sql表达式,它只能由String强转获得; 它可以隐式转换为所有基础对象,但只能在表达式树中使用, 如
    Where<User>(u => (SqlExpr)"@@identity" == 5); //@@identity = 5

 

对象定义

// 轻量级表达式树解析器 接口 public interface IFaller{    // 将表达式转为Where语句,不包含Where关键字    //saw: 自定义输出Sql语句的格式的对象    string ToWhere(ISaw saw);    // 将表达式转为OrderBy语句,不包含OrderBy关键字    //saw: 自定义输出Sql语句的格式的对象    //asc: 正序或倒序标识    string ToOrderBy(ISaw saw, bool asc);    // 将表达式转为Update中Set语句,不包含Set关键字    //saw: 自定义输出Sql语句的格式的对象    string ToSets(ISaw saw);    // 将表达式转为select语句中的列或列集合的Sql语句    //saw: 自定义输出Sql语句的格式的对象    string ToSelectColumns(ISaw saw);    // 将表达式转为值或值集合的sql语句    //saw: 自定义输出Sql语句的格式的对象    string ToValues(ISaw saw);    // 将表达式转为值或值集合的sql语句    //saw: 自定义输出Sql语句的格式的对象    string ToValues(ISaw saw, Func
replace); // 将表达式转为列集合和值集合2个sql语句,可用于拼装insert语句 //saw: 自定义输出Sql语句的格式的对象 KeyValuePair
ToColumnsAndValues(ISaw saw); // 转换Sql语句过程中产生的参数 ICollection
Parameters { get; }}
IFaller
///  定义一组方法,它支持自定义Sql语句的格式。    ///     public interface ISaw    {        ///  解释二元操作        ///         /// 左元素        /// 二元操作符        /// 右元素        string BinaryOperation(string left, BinaryOperator @operator, string right);        ///  解释Contains操作        ///         /// 是否为not        /// 要在集合中查找的对象        /// 要查找的集合        string ContainsOperation(bool not, string item, string[] array);        ///  向参数集合中追加一个任意类型的参数,并返回参数名sql表达式        ///         /// 需要追加的参数值        /// 参数集合        string AddObject(object obj, ICollection
parameters); ///
向参数集合中追加一个数字类型的参数,并返回参数名sql表达式 /// ///
需要追加的数字 ///
参数集合 string AddNumber(IConvertible number, ICollection
parameters); ///
向参数集合中追加一个布尔类型的参数,并返回参数名sql表达式 /// ///
需要追加的布尔值 ///
参数集合 string AddBoolean(bool value, ICollection
parameters); ///
向参数集合中追加当前时间,并返回参数名sql表达式 /// ///
参数集合 string AddTimeNow(ICollection
parameters); ///
获取实体类型所映射的表名 /// ///
实体类型 ///
别名 string GetTable(Type type, string alias); ///
获取实体属性或字段所映射的列名 /// ///
表名或表别名 ///
实体属性或字段 string GetColumn(string table, MemberInfo member); ///
获取列名和列别名组合后的sql表达式 /// ///
列名 ///
列别名 string GetColumn(string columnName, string alias); ///
将.NET中的方法解释为sql表达式 /// ///
需解释的方法 ///
方法调用者 ///
方法参数 ///
string ParseMethod(MethodInfo method, SawDust target, SawDust[] args); }
ISaw
///  表达式树解析结果    ///     public struct SawDust    {        ///  结果类型        ///         public readonly DustType Type;        ///  结果值        ///         public readonly Object Value;        ///  无论结果类型 强制转换为Sql语句,DustType.Undefined抛出异常        ///         public string ToSql();                ///   是否是非DustType.Sql和DustType.Undefined类型        ///         public bool IsObject { get;}    }
SawDust(不包含实现)
///  表达式解析结果类型    ///     [System.Serializable]    public enum DustType    {        ///  未知        ///         Undefined = 0,        ///  sql语句        ///         Sql = 1,        ///  未知类型        ///         Object = 2,        ///  数字        ///         Number = 3,        ///  数组        ///         Array = 4,        ///  布尔值        ///         Boolean = 5,        ///  时间        ///         DateTime = 6,        ///  二进制        ///         Binary = 7,        ///  字符串        ///         String = 8,    }
DustType
///  Sql表达式    ///     public struct SqlExpr    {        public static explicit operator SqlExpr(string value);        public static implicit operator bool(SqlExpr value);        public static implicit operator byte(SqlExpr value);        public static implicit operator char(SqlExpr value);        public static implicit operator DateTime(SqlExpr value);        public static implicit operator decimal(SqlExpr value);        public static implicit operator double(SqlExpr value);        public static implicit operator short(SqlExpr value);        public static implicit operator int(SqlExpr value);        public static implicit operator long(SqlExpr value);        public static implicit operator sbyte(SqlExpr value);        public static implicit operator float(SqlExpr value);        public static implicit operator string(SqlExpr value);        public static implicit operator ushort(SqlExpr value);        public static implicit operator uint(SqlExpr value);        public static implicit operator ulong(SqlExpr value);        public static implicit operator Guid(SqlExpr value);        public static implicit operator Byte[](SqlExpr value);    }
SqlExpr

 

///  支持自定义Sql语句格式基类。    ///     public abstract class BaseSaw : ISaw    {        ///  初始化并提供 DbProviderFactory        ///         ///         protected BaseSaw(DbProviderFactory factory);        /*         * 接口已定义方法略...         */        ///  解释未知的方法        ///         /// 需解释的方法        /// 方法调用者        /// 方法参数        protected virtual string ParseUnknownMethod(MethodInfo method, SawDust target, SawDust[] args);        ///  获取新的数据库参数        ///         /// 参数值        protected virtual DbParameter GetDbParameter(object obj);        ///  别名分隔符 默认 AS ,如 Table AS it        ///         protected virtual string AliasSeparator { get; }        ///  解释按位运算 与,或,非        ///         /// 操作数1        /// 操作数2        /// 按位操作符        protected virtual string BitOperation(string val1, string val2, BitOperator opt);        ///  解释取余运算        ///         /// 操作数1        /// 操作数2        /// 
protected virtual string ModuloOperation(string val1, string val2); /// 解释幂运算 /// /// 操作数1 /// 操作数2 ///
protected virtual string PowerOperation(string val1, string val2); /// 解释位移运算 /// /// 操作数1 /// 操作数2 /// 按位操作符 protected virtual string ShiftOperation(string val1, string val2, ShiftOperator opt); /// 解释 String.Trim 方法 /// /// 方法调用者 /// 方法参数 protected virtual string StringTrim(string target, string arg); /// 解释 String.TrimEnd 方法 /// /// 方法调用者 /// 方法参数 protected virtual string StringTrimEnd(string target, string arg); /// 解释 String.TrimStart 方法 /// /// 方法调用者 /// 方法参数 protected virtual string StringTrimStart(string target, string arg); /// 解释 String.IsNullOrEmpty 方法 /// /// 方法调用者 protected virtual string StringIsNullOrEmpty(string target); /// 解释 String.IsNullOrWhiteSpace 方法 /// /// 方法调用者 protected virtual string StringIsNullOrWhiteSpace(string target); /// 解释 String.Length 方法 /// /// 方法调用者 protected virtual string StringLength(string target); /// 解释 Object.ToString 方法 /// /// 调用者类型 /// 方法调用者 /// 格式化参数 protected virtual string ObjectToString(DustType type, string target, string format); /// 解释 DateTime 中的数据 /// /// 方法调用者 protected virtual string DateTimeToField(string datetime, DateTimeField field); /// 解释各种 Number.Parse 方法 /// /// string对象 protected virtual string SrtingToNumber(string target); #region abstract /// 返回实体类型所映射的表名 /// /// 实体类型 protected abstract string TableName(Type type); /// 返回实体属性或字段所映射的列名 /// /// 实体属性或字段 protected abstract string ColumnName(MemberInfo member); /// 参数的前缀符号,如SqlServer中的@,Oracle中的: /// protected abstract string ParameterPreFix { get; } /// 在数据库中表示当前时间的表达式,如SqlServer中的getdate,Oracle中的SYSDATE /// protected abstract string TimeNow { get; } /// 解释Like操作 /// /// 操作数1 /// 操作数2 /// 按位操作符 protected abstract string LikeOperation(string val1, string val2, LikeOperator opt); #endregion }
BaseSaw(不包含实现)
///  二元操作符枚举    ///     [Serializable]    public enum BinaryOperator    {        ///  加        ///         Add,        ///  减        ///         Subtract,        ///  除        ///         Divide,        ///  取余        ///         Modulo,        ///  乘        ///         Multiply,        ///  幂运算        ///         Power,        ///  位移运算 a << b        ///         LeftShift,        ///  位移运算 a >> b        ///         RightShift,        ///  与 a && b 或 a AND b        ///         And,        ///  或 a || b 或 a OR b        ///         Or,        ///  等于 a == b        ///         Equal,        ///  不等于 a != b 或 a <> b        ///         NotEqual,        ///  大于 a > b        ///         GreaterThan,        ///  大于等于 a >= b        ///         GreaterThanOrEqual,        ///  小于 a < b        ///         LessThan,        ///  小于等于 a <= b        ///         LessThanOrEqual,        ///  LIKE操作 a LIKE %b%        ///             Contains,                 ///  LIKE操作 a LIKE b%        ///             StartWith,                ///  LIKE操作 a LIKE %b        ///             EndWith,                  ///  LIKE操作 a NOT LIKE %b%        ///             NotContains,              ///  LIKE操作 a NOT LIKE b%        ///             NotStartWith,             ///  LIKE操作 a NOT LIKE %b        ///         NotEndWith,        ///  位运算 如 a & b        ///         BitAnd,        ///  位运算 如 a | b        ///         BitOr,        ///  位运算 如 a ^ b        ///         BitXor,    }    ///  按位操作符枚举    ///     [Serializable]    public enum BitOperator    {        ///  位运算 如 a & b        ///         And,        ///  位运算 如 a | b        ///         Or,        ///  位运算 如 a ^ b        ///         Xor,    }    ///  Like操作符枚举    ///     [Serializable]    public enum LikeOperator    {        ///  LIKE操作 a LIKE %b%        ///             Contains,        ///  LIKE操作 a LIKE b%        ///             StartWith,        ///  LIKE操作 a LIKE %b        ///             EndWith,        ///  LIKE操作 a NOT LIKE %b%        ///             NotContains,        ///  LIKE操作 a NOT LIKE b%        ///             NotStartWith,        ///  LIKE操作 a NOT LIKE %b        ///         NotEndWith,    }    ///  位移操作符枚举    ///     [Serializable]    public enum ShiftOperator    {                 ///  位移运算 a << b        ///         Left,        ///  位移运算 a >> b        ///         Right,    }    ///  时间字段    ///     [Serializable]    public enum DateTimeField    {        ///  年        ///         Year,        ///  月        ///         Month,        ///  日        ///         Day,        ///  时        ///         Hour,        ///  分        ///         Minute,        ///  秒        ///         Second,        ///  星期        ///         Week,    }
其他枚举

 

再来一个已实现的MsSqlSaw

public class MsSqlSaw : BaseSaw    {        public static MsSqlSaw Instance = new MsSqlSaw();        private MsSqlSaw() : base(System.Data.SqlClient.SqlClientFactory.Instance) { }        private static HashSet
KeyWords = InitKeyWords(); private static HashSet
InitKeyWords() { return new HashSet
("ABSOLUTE,ACTION,ADA,ADD,ADMIN,AFTER,AGGREGATE,ALIAS,ALL,ALLOCATE,ALTER,AND,ANY,ARE,ARRAY,AS,ASC,ASSERTION,AT,AUTHORIZATION,AVG,BACKUP,BEFORE,BEGIN,BETWEEN,BINARY,BIT,BIT_LENGTH,BLOB,BOOLEAN,BOTH,BREADTH,BREAK,BROWSE,BULK,BY,CALL,CASCADE,CASCADED,CASE,CAST,CATALOG,CHAR,CHARACTER,CHARACTER_LENGTH,CHAR_LENGTH,CHECK,CHECKPOINT,CLASS,CLOB,CLOSE,CLUSTERED,COALESCE,COLLATE,COLLATION,COLUMN,COMMIT,COMPLETION,COMPUTE,CONNECT,CONNECTION,CONSTRAINT,CONSTRAINTS,CONSTRUCTOR,CONTAINS,CONTAINSTABLE,CONTINUE,CONVERT,CORRESPONDING,COUNT,CREATE,CROSS,CUBE,CURRENT,CURRENT_DATE,CURRENT_PATH,CURRENT_ROLE,CURRENT_TIME,CURRENT_TIMESTAMP,CURRENT_USER,CURSOR,CYCLE,DATA,DATABASE,DATE,DAY,DBCC,DEALLOCATE,DEC,DECIMAL,DECLARE,DEFAULT,DEFERRABLE,DEFERRED,DELETE,DENY,DEPTH,DEREF,DESC,DESCRIBE,DESCRIPTOR,DESTROY,DESTRUCTOR,DETERMINISTIC,DIAGNOSTICS,DICTIONARY,DISCONNECT,DISK,DISTINCT,DISTRIBUTED,DOMAIN,DOUBLE,DROP,DUMMY,DUMP,DYNAMIC,EACH,ELSE,END,END-EXEC,EQUALS,ERRLVL,ESCAPE,EVERY,EXCEPT,EXCEPTION,EXEC,EXECUTE,EXISTS,EXIT,EXTERNAL,EXTRACT,FALSE,FETCH,FILE,FILLFACTOR,FIRST,FLASE,FLOAT,FOR,FOREIGN,FORTRAN,FOUND,FREE,FREETEXT,FREETEXTTABLE,FROM,FULL,FUNCTION,GENERAL,GET,GLOBAL,GO,GOTO,GRANT,GROUP,GROUPING,HAVING,HOLDLOCK,HOST,HOUR,IDENTITY,IDENTITYCOL,IDENTITY_INSERT,IF,IGNORE,IMMEDIATE,IN,INCLUDE,INDEX,INDICATOR,INITIALIZE,INITIALLY,INNER,INOUT,INPUT,INSENSITIVE,INSERT,INT,INTEGER,INTERSECT,INTERVAL,INTO,IS,ISOLATION,ITERATE,JOIN,KEY,KILL,LANGUAGE,LARGE,LAST,LATERAL,LEADING,LEFT,LESS,LEVEL,LIKE,LIMIT,LINENO,LOAD,LOCAL,LOCALTIME,LOCALTIMESTAMP,LOCATOR,LOWER,MAP,MATCH,MAX,MIN,MINUTE,MODIFIES,MODIFY,MODULE,MONTH,NAMES,NATIONAL,NATURAL,NCHAR,NCLOB,NEW,NEXT,NO,NOCHECK,NONCLUSTERED,NONE,NOT,NULL,NULLIF,NUMERIC,OBJECT,OCTET_LENGTH,OF,OFF,OFFSETS,OLD,ON,ONLY,OPEN,OPENDATASOURCE,OPENQUERY,OPENROWSET,OPENXML,OPERATION,OPTION,OR,ORDER,ORDINALITY,OUT,OUTER,OUTPUT,OVER,OVERLAPS,PAD,PARAMETER,PARAMETERS,PARTIAL,PASCAL,PATH,PERCENT,PLAN,POSITION,POSTFIX,PRECISION,PREFIX,PREORDER,PREPARE,PRESERVE,PRIMARY,PRINT,PRIOR,PRIVILEGES,PROC,PROCEDURE,PUBLIC,RAISERROR,READ,READS,READTEXT,REAL,RECONFIGURE,RECURSIVE,REF,REFERENCES,REFERENCING,RELATIVE,REPLICATION,RESTORE,RESTRICT,RESULT,RETURN,RETURNS,REVOKE,RIGHT,ROLE,ROLLBACK,ROLLUP,ROUTINE,ROW,ROWCOUNT,ROWGUIDCOL,ROWS,RULE,SAVE,SAVEPOINT,SCHEMA,SCOPE,SCROLL,SEARCH,SECOND,SECTION,SELECT,SEQUENCE,SESSION,SESSION_USER,SET,SETS,SETUSER,SHUTDOWN,SIZE,SMALLINT,SOME,SPACE,SPECIFIC,SPECIFICTYPE,SQL,SQLCA,SQLCODE,SQLERROR,SQLEXCEPTION,SQLSTATE,SQLWARNING,START,STATE,STATEMENT,STATIC,STATISTICS,STRUCTURE,SUBSTRING,SUM,SYSTEM_USER,TABLE,TEMPORARY,TERMINATE,TEXTSIZE,THAN,THEN,TIME,TIMESTAMP,TIMEZONE_HOUR,TIMEZONE_MINUTE,TO,TOP,TRAILING,TRAN,TRANSACTION,TRANSLATE,TRANSLATION,TREAT,TRIGGER,TRIM,TRUE,TRUNCATE,TSEQUAL,UNDER,UNION,UNIQUE,UNKNOWN,UNNEST,UPDATE,UPDATETEXT,UPPER,USAGE,USE,USER,USING,VALUE,VALUES,VARCHAR,VARIABLE,VARYING,VIEW,WAITFOR,WHEN,WHENEVER,WHERE,WHILE,WITH,WITHOUT,WORK,WRITE,WRITETEXT,YEAR,ZONE".Split(','), StringComparer.OrdinalIgnoreCase); } protected override string TableName(Type type) { var name = type.Name; if (KeyWords.Contains(name)) { return string.Concat("[", name, "]"); } return name; } protected override string ColumnName(MemberInfo member) { var name = member.Name; if (KeyWords.Contains(name)) { return string.Concat("[", name, "]"); } return name; } protected override string ParameterPreFix { get { return "@"; } } protected override string TimeNow { get { return "GETDATE()"; } } protected override string LikeOperation(string val1, string val2, LikeOperator opt) { switch (opt) { case LikeOperator.Contains: return string.Concat(val1, " LIKE '%' + ", val2, " + '%'"); case LikeOperator.StartWith: return string.Concat(val1, " LIKE ", val2, " + '%'"); case LikeOperator.EndWith: return string.Concat(val1, " LIKE '%' + ", val2); case LikeOperator.NotContains: return string.Concat(val1, " NOT LIKE '%' + ", val2, " + '%'"); case LikeOperator.NotStartWith: return string.Concat(val1, " NOT LIKE ", val2, " + '%'"); case LikeOperator.NotEndWith: return string.Concat(val1, " NOT LIKE '%' + ", val2); default: throw new ArgumentOutOfRangeException("opt"); } } protected override string BitOperation(string val1, string val2, BitOperator opt) { switch (opt) { case BitOperator.And: return string.Concat(val1, " & ", val2); case BitOperator.Or: return string.Concat(val1, " | ", val2); case BitOperator.Xor: return string.Concat(val1, " ^ ", val2); default: throw new ArgumentOutOfRangeException("opt"); } } protected override string StringTrim(string target, string arg) { if (arg != null) { throw new NotSupportedException("不支持参数"); } return string.Concat("LTRIM(RTRIM(", target, "))"); } protected override string StringTrimEnd(string target, string arg) { if (arg != null) { throw new NotSupportedException("不支持参数"); } return string.Concat("RTRIM(", target, ")"); } protected override string StringTrimStart(string target, string arg) { if (arg != null) { throw new NotSupportedException("不支持参数"); } return string.Concat("LTRIM(", target, ")"); } protected override string StringLength(string target) { return string.Concat("LEN(", target, ")"); } protected override string SrtingToNumber(string target) { return string.Concat("CAST(", target, " as decimal)"); } protected override string ObjectToString(DustType type, string target, string format) { switch (type) { case DustType.Undefined: break; case DustType.Sql: break; case DustType.Object: break; case DustType.Number: if (format != null) { throw new NotSupportedException("不支持参数"); } return string.Concat("CAST(", target, " as NVARCHAR)"); case DustType.Array: break; case DustType.Boolean: break; case DustType.DateTime: switch (format) { case "'HH:mm'": return string.Concat("CONVERT(VARCHAR(5),", target, ",114)"); case "'HH:mm:ss'": return string.Concat("CONVERT(VARCHAR(8),", target, ",114)"); case "'HH:mm:ss.fff'": return string.Concat("CONVERT(VARCHAR(12),", target, ",114)"); case "'yyyy-MM-dd'": return string.Concat("CONVERT(VARCHAR(10),", target, ",21)"); case "'yyyy-MM-dd HH:mm'": return string.Concat("CONVERT(VARCHAR(16),", target, ",21)"); case "'yyyy-MM-dd HH:mm:ss'": return string.Concat("CONVERT(VARCHAR(19),", target, ",21)"); case "'yyyy-MM-dd HH:mm:ss.fff'": return string.Concat("CONVERT(VARCHAR(23),", target, ",21)"); case "'yy/MM/dd'": return string.Concat("CONVERT(VARCHAR(8),", target, ",111)"); case "'yyMMdd'": return string.Concat("CONVERT(VARCHAR(6),", target, ",112)"); default: break; } throw new NotSupportedException("不支持当前参数"); case DustType.Binary: break; case DustType.String: break; default: break; } return base.ObjectToString(type, target, format); } protected override string DateTimeToField(string datetime, DateTimeField field) { switch (field) { case DateTimeField.Year: return string.Concat("DATEPART(YYYY, ", datetime, ")"); case DateTimeField.Month: return string.Concat("DATEPART(mm, ", datetime, ")"); case DateTimeField.Day: return string.Concat("DATEPART(dd, ", datetime, ")"); case DateTimeField.Hour: return string.Concat("DATEPART(hh, ", datetime, ")"); case DateTimeField.Minute: return string.Concat("DATEPART(mi, ", datetime, ")"); case DateTimeField.Second: return string.Concat("DATEPART(ss, ", datetime, ")"); case DateTimeField.Week: return string.Concat("(DATEPART(w, ", datetime, ") - 1)"); default: throw new ArgumentOutOfRangeException("field"); } } }
MsSqlSaw

 

部分解释结果展示(以OracleSaw为例)

下载地址

广告

对C#感兴趣的朋友可以来群里讨论,入群方式见签名

转载地址:http://dwcka.baihongyu.com/

你可能感兴趣的文章
[转载] 七龙珠第一部——第058话 魔境圣地
查看>>
【总结整理】JQuery基础学习---样式篇
查看>>
查询个人站点的文章、分类和标签查询
查看>>
基础知识:数字、字符串、列表 的类型及内置方法
查看>>
JSP的隐式对象
查看>>
P127、面试题20:顺时针打印矩阵
查看>>
JS图片跟着鼠标跑效果
查看>>
[SCOI2005][BZOJ 1084]最大子矩阵
查看>>
学习笔记之Data Visualization
查看>>
Leetcode 3. Longest Substring Without Repeating Characters
查看>>
【FJOI2015】金币换位问题
查看>>
数学之美系列二十 -- 自然语言处理的教父 马库斯
查看>>
Android实现自定义位置无标题Dialog
查看>>
面试总结
查看>>
Chrome浏览器播放HTML5音频没声音的解决方案
查看>>
easyui datagrid 行编辑功能
查看>>
类,对象与实例变量
查看>>
HDU 2818 (矢量并查集)
查看>>
【转】php字符串加密解密
查看>>
22. linux 常用命令
查看>>