• EasyFastCMS系列教学课程——2、底层代码 ModelHelper与SQLHelper简介


    从本节课开始,我们开始逐步正式进入实际的编码过程中。本节课的核心内容为SQLHeelper和ModelHelper两个核心类库的介绍。

    SQLHelper这个类相信大家都很熟悉了,他是微软petshop示例项目中对数据库操作(ado.net)的一个封装。我们对这个类做了一个改进:

    if ((parm.Value == null) || (string.IsNullOrEmpty(parm.Value.ToString())))
    {
    parm.Value = DBNull.Value;
    }

    这里涉及了空和null的区别。我们知道,程序都是在内存中运行的。空和null的区别其实也提现在内存中。在系统中,内存整体上分了两个区域,一块存储索引,一块存储内容(注:以上说明并不严谨,只是为了方便理解做的简化说明。实质上在net环境下,内存有堆、栈、托管堆等区分,参见:http://blog.csdn.net/xiongwjw/article/details/7248613 )

    0-1 0-2 0-3 0-4
    1-1 1-2 1-3 1-4
    A(0-1) B(0-2) C(0-3) D(0-4)
    E(1-1) F(1-2) G(1-3) (1-4)

    空:在内存中分配了索引,但是索引对应的实质存储位置没有数据,例如1-4这个索引的情况,虽然分配了索引,但是索引所对应的实际存储位置没有数据。

    Null:连索引也没有分配,完全没有任何内容。

    我们增加的if判断主要用于一些输入框没有输入值时,直接在数据库中赋值 DBNull.Value。这样可以防止实际的参数数量和sql语句中规定的参数数量不一致。

    在ModelHelper这个类库中,我们创建了四个属性,分别是TableName、PrimaryKey、ModelGuid、TimeStamp。这四个值我们都是通过反射得到的,这里其实包含了一个我们对数据库表的一个约定:

    • 数据库表的第一个必须为自增ID;
    • 数据库表的第二列必须为Guid类型(如果将来在程序中不适用ModelGuid这个属性,则可以忽略此处);
    • 数据库表的最后一列必须为TimeStamp类型;

    有些同学可能奇怪,为什么有了自增ID还要创建Guid,这个设置主要是用来恢复删除的数据使用的。比如有一条数据,他的ID是3,删除这条数据后,表中又添加了一些数据,某天,突然要恢复这条数据,将它从已删除中恢复到正常数据表里,这时,受限于主键自增的约束,我们在add这条数据时,ID肯定不为3了。那么为什么唯一确定这条数据的身份证就是Guid了。但是,我们都知道Guid是32位的数字字母混合形式的,虽然具有唯一性,但是不具备可读性,尤其麻烦的是,无法排序。这时,自增ID就会用得到了。从视频中我们可以发现,该项设定其实是移植自一套OA系统中的,这套OA系统有很多复杂的逻辑,功能也很强大,其中就包含了关键业务数据的删除恢复这个功能。我们在网站中,其实也会遇到重要数据删除后想恢复的情况,所以这个设定就保留了下来。

    数据表中的最后一列为TimeStamp类型是为了考虑并发而设计的。比如A打开了一个用户——张三的信息进行编辑,然后提交。在A编辑(尚未提交时)的过程中,B也在编辑这条数据,并且先A一步进行了提交操作。这时系统有两种选择,1是直接保存A的编辑数据,覆盖B的编辑结果;2是进行提醒:该数据已经被B编辑过了,新的数据值为XXX,您是否仍要保存您的编辑结果?在一般的系统中,我们都是采用第一种方案,但是在一些关键系统的关键数据中,采用第一种方案是有很大风险性的,很容易造成数据失误,必须采用第二种方案。那么我们如何知道B编辑过数据了呢?这时,TimeStamp就用上场了。在MySQL中,TimeStamp是一种DateTime格式,在MSSQL中,TimeStamp是一串二进制值(两者可以互相转化MSSQL中的二进制值相当于序列化后的DateTime格式,我也很奇怪为什么MSSQL不直接使用DateTime,如果哪位亲有认识MSSQL的开发人员,记得帮我问下)。TimeStamp列有个特殊属性,一旦数据库中的记录发生过改动,TimeStamp的值一定会发生改变这样我们只要在update时判断下元数据的TimeStamp值是否发生过改变,就能确定该数据是否被编辑过。

    在ModelHelper类中,我们引入了两个命名空间:

    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;

    这两个命名空间是MVC的M部分常用的数据约束。我们主要用于确定SqlParameter的长度。.Net本质上是一大套类库+一种运行方式。Webform和MVC之间并非完全隔离不可互通的。MVC本质上是一种软件架构模式,如果有必要,WebForm也可以实现MVC模式。所以一直犹豫WebForm或是MVC的同学大可以放下你的担心,这两者都很优秀,都能解决问题。我们引入这两个命名空间的主要用途如下:

     1 public SqlParameter GetSqlParameter(PropertyInfo pi,T model)
     2         {
     3             SqlParameter parameter;
     4             switch (pi.PropertyType.Name)
     5             {
     6                 case "String":
     7                     int length = 0;
     8                     object[] attributes = pi.GetCustomAttributes(typeof(StringLengthAttribute), true);
     9                     if (attributes != null && attributes.Length > 0)
    10                     {
    11                         StringLengthAttribute myAttribute = attributes[0] as StringLengthAttribute;
    12                         if (myAttribute != null)
    13                         {
    14                             length = myAttribute.MaximumLength;
    15                         }
    16                     }
    17                     if (length != 0)
    18                     {
    19                         parameter = new SqlParameter("@" + pi.Name, SqlDbType.NVarChar, length);
    20                     }
    21                     else
    22                     {
    23                         parameter = new SqlParameter("@" + pi.Name, SqlDbType.NVarChar);
    24                     }
    25                     parameter.Value = pi.GetValue(model, null);
    26                     break;
    27                 case "Int32":
    28                     parameter = new SqlParameter("@" + pi.Name, SqlDbType.Int, 4);
    29                     parameter.Value = pi.GetValue(model, null);
    30                     break;
    31                 case "Int64":
    32                     parameter = new SqlParameter("@" + pi.Name, SqlDbType.BigInt, 8);
    33                     parameter.Value = pi.GetValue(model, null);
    34                     break;
    35                 case "DataTime":
    36                     parameter = new SqlParameter("@" + pi.Name, SqlDbType.DateTime, 8);
    37                     parameter.Value = pi.GetValue(model, null);
    38                     break;
    39                 case "Boolean":
    40                     parameter = new SqlParameter("@" + pi.Name, SqlDbType.Bit, 2);
    41                     parameter.Value = pi.GetValue(model, null);
    42                     break;
    43                 case "Guid":
    44                     parameter = new SqlParameter("@" + pi.Name, SqlDbType.UniqueIdentifier, 16);
    45                     parameter.Value = pi.GetValue(model, null);
    46                     break;
    47                 case "Byte":
    48                     parameter = new SqlParameter("@" + pi.Name, SqlDbType.Timestamp, 8);
    49                     parameter.Value = pi.GetValue(model, null);
    50                     break;
    51                 default:
    52                     parameter = new SqlParameter("@" + pi.Name, pi.GetValue(model, null));
    53                     break;
    54             }
    55             return parameter;
    56         }

    我们通过反射,获取model上的stringlength属性,通过这个属性的值来确定SqlParameter的长度。我在博客园上曾经看到一篇文章,MSSQL中,如果不指定参数的长度,就无法做到执行计划的复用,每次都要编译,其效率并不比直接写SQL语句高多少,我没有实际做过测试,但我感觉对方说的有道理,喜欢刨根挖底的朋友建议在园子里搜搜这篇文章,自己亲自做个测试,当然了,有结果也请告知我一下^&^。

    在ModelHelper的代码中,我们还是用到了缓存,缓存的主要代码我就不贴了。核心的关键有两个:

    1:单例模式的双重锁定,园子里有篇文章列举过单例模式的几种实现,我唯一能确定的是,双重锁定是能可以确保线程安全的(static静态变量的似乎也可以),至于其他的,大家可以搜搜看,在那篇文章中有测试。

    2:戴振军同学曾贡献过discuz的缓存设计架构http://www.cnblogs.com/daizhj/archive/2007/08/15/855163.html 这篇文章相对好理解,他们实质上是在内存中虚拟了一个“XML DOM树”,将不同的缓存放在不同的节点下,这样可以方便的集中管理缓存,同时他们还实现了策略模式,戴同学讲的很透彻,大家仔细看下这篇文章,一定不难理解的。我们的缓存设计的主要特点是采用了.net4.0的新增类库System.Runtime.Caching 微软已宣传在后续的net版本中,将主要维护这个类库,原System.Web.Cache将不再维护,建议大家日后使用新类库。另一个特点是我们使用了数据库缓存依赖。就我个人所知而言,这个设计是及其伟大的,微软我爱你,盖茨,你虽然不帅,我照样爱你。缓存最大的问题在于时效性问题,也就是我们常说的脏数据问题。net的数据库缓存依赖可以做到当数据库数据改变以后,SQL通过一个叫做”查询通知“的功能告知NET运行时:Hi,老兄,你的数据已过期了,赶紧删除吧!(我也好奇,为什么叫查询通知而不叫更新通知,难道是翻译问题?)通过这点,我们可以做到缓存效率和时效性的完美平衡,一个没有脏数据的缓存实在实在是太诱人了!!!缓存依赖不仅仅支持数据库缓存依赖,还支持文件缓存依赖(当文件的最后更新时间改变后,缓存自动失效),甚至可以自定义依赖策略!!!

    我们在日后会借鉴戴振军同学贡献的缓存架构并做适当的修改已更加适应cms程序,受限于我们是入门级教程,初期我们就直接以net默认的键值对方式使用,后期再做改进,同时,日后我们也会考虑增加Memcached的使用和配置。

    补充:数据库缓存依赖:http://www.cnblogs.com/jackyzhou/archive/2009/04/21/1440483.html

      1 using System;
      2 using System.Collections;
      3 using System.Collections.Specialized;
      4 using System.Data;
      5 using System.Data.SqlClient;
      6 using System.Configuration;
      7 using System.Data.Common;
      8 using System.Collections.Generic;
      9 using System.IO;
     10 using System.Text;
     11 
     12 namespace EasyFast.Repository
     13 {
     14     /// <summary>
     15     /// SqlHelper类是专门提供给广大用户用于高性能、可升级和最佳练习的sql数据操作
     16     /// </summary>
     17     public abstract class SqlHelper
     18     {
     19         //数据库连接字符串
     20         public static readonly string ConnectionString = ConfigurationManager.ConnectionStrings["DataBase"].ConnectionString;
     21 
     22         // 用于缓存参数的HASH表
     23         private static Hashtable parmCache = Hashtable.Synchronized(new Hashtable());
     24 
     25         /// <summary>
     26         ///  给定连接的数据库用假设参数执行一个sql命令(不返回数据集)
     27         /// </summary>
     28         /// <param name="connectionString">一个有效的连接字符串</param>
     29         /// <param name="commandType">命令类型(存储过程, 文本, 等等)</param>
     30         /// <param name="commandText">存储过程名称或者sql命令语句</param>
     31         /// <param name="commandParameters">执行命令所用参数的集合</param>
     32         /// <returns>执行命令所影响的行数</returns>
     33         public static int ExecuteNonQuery(string connectionString, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters)
     34         {
     35             SqlCommand cmd = new SqlCommand();
     36             using (SqlConnection conn = new SqlConnection(connectionString))
     37             {
     38                 PrepareCommand(cmd, conn, null, cmdType, cmdText, commandParameters);
     39                 int val = cmd.ExecuteNonQuery();
     40                 cmd.Parameters.Clear();
     41                 return val;
     42             }
     43         }
     44 
     45         /// <summary>
     46         /// 用现有的数据库连接执行一个sql命令(不返回数据集)
     47         /// </summary>
     48         /// <param name="conn">一个现有的数据库连接</param>
     49         /// <param name="commandType">命令类型(存储过程, 文本, 等等)</param>
     50         /// <param name="commandText">存储过程名称或者sql命令语句</param>
     51         /// <param name="commandParameters">执行命令所用参数的集合</param>
     52         /// <returns>执行命令所影响的行数</returns>
     53         public static int ExecuteNonQuery(SqlConnection connection, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters)
     54         {
     55             SqlCommand cmd = new SqlCommand();
     56             PrepareCommand(cmd, connection, null, cmdType, cmdText, commandParameters);
     57             int val = cmd.ExecuteNonQuery();
     58             cmd.Parameters.Clear();
     59             return val;
     60         }
     61 
     62         /// <summary>
     63         ///使用现有的SQL事务执行一个sql命令(不返回数据集)
     64         /// </summary>
     65         /// <remarks>
     66         ///举例:  
     67         ///  int result = ExecuteNonQuery(connString, CommandType.StoredProcedure, "PublishOrders", new SqlParameter("@prodid", 24));
     68         /// </remarks>
     69         /// <param name="trans">一个现有的事务</param>
     70         /// <param name="commandType">命令类型(存储过程, 文本, 等等)</param>
     71         /// <param name="commandText">存储过程名称或者sql命令语句</param>
     72         /// <param name="commandParameters">执行命令所用参数的集合</param>
     73         /// <returns>执行命令所影响的行数</returns>
     74         public static int ExecuteNonQuery(SqlTransaction trans, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters)
     75         {
     76             SqlCommand cmd = new SqlCommand();
     77             PrepareCommand(cmd, trans.Connection, trans, cmdType, cmdText, commandParameters);
     78             int val = cmd.ExecuteNonQuery();
     79             cmd.Parameters.Clear();
     80             return val;
     81         }
     82 
     83         /// <summary>
     84         /// 用指定的数据库连接执行一个返回数据集的sql命令
     85         /// </summary>
     86         /// <remarks>
     87         /// 举例:  
     88         ///  SqlDataReader r = ExecuteReader(connString, CommandType.StoredProcedure, "PublishOrders", new SqlParameter("@prodid", 24));
     89         /// </remarks>
     90         /// <param name="connectionString">一个有效的连接字符串</param>
     91         /// <param name="commandType">命令类型(存储过程, 文本, 等等)</param>
     92         /// <param name="commandText">存储过程名称或者sql命令语句</param>
     93         /// <param name="commandParameters">执行命令所用参数的集合</param>
     94         /// <returns>包含结果的读取器</returns>
     95         public static SqlDataReader ExecuteReader(string connectionString, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters)
     96         {
     97             //创建一个SqlCommand对象
     98             SqlCommand cmd = new SqlCommand();
     99             //创建一个SqlConnection对象
    100             SqlConnection conn = new SqlConnection(connectionString);
    101 
    102             //在这里我们用一个try/catch结构执行sql文本命令/存储过程,因为如果这个方法产生一个异常我们要关闭连接,因为没有读取器存在,
    103             //因此commandBehaviour.CloseConnection 就不会执行
    104             try
    105             {
    106                 //调用 PrepareCommand 方法,对 SqlCommand 对象设置参数
    107                 PrepareCommand(cmd, conn, null, cmdType, cmdText, commandParameters);
    108                 //调用 SqlCommand  的 ExecuteReader 方法
    109                 SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
    110                 //清除参数
    111                 cmd.Parameters.Clear();
    112                 return reader;
    113             }
    114             catch
    115             {
    116                 //关闭连接,抛出异常
    117                 conn.Close();
    118                 throw;
    119             }
    120         }
    121 
    122         /// <summary>
    123         /// 用指定的数据库连接字符串执行一个命令并返回一个数据集的第一列
    124         /// </summary>
    125         /// <remarks>
    126         ///例如:  
    127         ///  Object obj = ExecuteScalar(connString, CommandType.StoredProcedure, "PublishOrders", new SqlParameter("@prodid", 24));
    128         /// </remarks>
    129         ///<param name="connectionString">一个有效的连接字符串</param>
    130         /// <param name="commandType">命令类型(存储过程, 文本, 等等)</param>
    131         /// <param name="commandText">存储过程名称或者sql命令语句</param>
    132         /// <param name="commandParameters">执行命令所用参数的集合</param>
    133         /// <returns>用 Convert.To{Type}把类型转换为想要的 </returns>
    134         public static object ExecuteScalar(string connectionString, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters)
    135         {
    136             using (SqlConnection connection = new SqlConnection(connectionString))
    137             {
    138                 SqlCommand cmd = new SqlCommand();
    139                 PrepareCommand(cmd, connection, null, cmdType, cmdText, commandParameters);
    140                 object val = cmd.ExecuteScalar();
    141                 cmd.Parameters.Clear();
    142                 return val;
    143             }
    144         }
    145 
    146         /// <summary>
    147         /// 用现有的SQL事务执行一个sql命令,返回数据集的第一列
    148         /// </summary>
    149         /// <param name="trans">一个现有的事务</param>
    150         /// <param name="commandType">命令类型(存储过程, 文本, 等等)</param>
    151         /// <param name="commandText">存储过程名称或者sql命令语句</param>
    152         /// <param name="commandParameters">执行命令所用参数的集合</param>
    153         /// <returns>数据集的第一列</returns>
    154         public static object ExecuteScalar(SqlTransaction trans, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters)
    155         {
    156             SqlCommand cmd = new SqlCommand();
    157             PrepareCommand(cmd, trans.Connection, trans, cmdType, cmdText, commandParameters);
    158             object val = cmd.ExecuteScalar();
    159             cmd.Parameters.Clear();
    160             return val;
    161         }
    162 
    163         /// <summary>
    164         /// 用现有的数据库连接执行一个命令并返回一个数据集的第一列
    165         /// </summary>
    166         /// <remarks>
    167         /// 例如:  
    168         ///  Object obj = ExecuteScalar(connString, CommandType.StoredProcedure, "PublishOrders", new SqlParameter("@prodid", 24));
    169         /// </remarks>
    170         /// <param name="conn">一个存在的数据库连接</param>
    171         /// <param name="commandType">命令类型(存储过程, 文本, 等等)</param>
    172         /// <param name="commandText">存储过程名称或者sql命令语句</param>
    173         /// <param name="commandParameters">执行命令所用参数的集合</param>
    174         /// <returns>用 Convert.To{Type}把类型转换为想要的 </returns>
    175         public static object ExecuteScalar(SqlConnection connection, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters)
    176         {
    177             SqlCommand cmd = new SqlCommand();
    178             PrepareCommand(cmd, connection, null, cmdType, cmdText, commandParameters);
    179             object val = cmd.ExecuteScalar();
    180             cmd.Parameters.Clear();
    181             return val;
    182         }
    183 
    184         /// <summary>
    185         /// 根据指定的数据库连接字符串返回一个DataSet
    186         /// </summary>
    187         /// <param name="connectionString">数据库连接字符串</param>
    188         /// <param name="commandType">命令类型(存储过程, 文本, 等等)</param>
    189         /// <param name="commandText">存储过程名称或者sql命令语句</param>
    190         /// <param name="commandParameters">执行命令所用参数的集合</param>
    191         /// <returns>DataSet</returns>
    192         public static DataSet GetDataSet(string connectionString, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters)
    193         {
    194             using (SqlConnection conn = new SqlConnection(connectionString))
    195             {
    196                 SqlCommand cmd = new SqlCommand();
    197                 PrepareCommand(cmd, conn, null, cmdType, cmdText, commandParameters);
    198                 SqlDataAdapter da = new SqlDataAdapter(cmd);
    199                 DataSet ds = new DataSet();
    200                 da.Fill(ds);
    201                 cmd.Parameters.Clear();
    202                 return ds;
    203             }
    204         }
    205 
    206         /// <summary>
    207         /// 根据指定的数据库连接字符串返回一个DataTable
    208         /// </summary>
    209         /// <param name="connectionString">数据库连接字符串</param>
    210         /// <param name="commandType">命令类型(存储过程, 文本, 等等)</param>
    211         /// <param name="commandText">存储过程名称或者sql命令语句</param>
    212         /// <param name="commandParameters">执行命令所用参数的集合</param>
    213         /// <returns>DataTable</returns>
    214         public static DataTable GetDataTable(string connectionString, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters)
    215         {
    216             using (SqlConnection conn = new SqlConnection(connectionString))
    217             {
    218                 SqlCommand cmd = new SqlCommand();
    219                 PrepareCommand(cmd, conn, null, cmdType, cmdText, commandParameters);
    220                 SqlDataAdapter da = new SqlDataAdapter(cmd);
    221                 DataSet ds = new DataSet();
    222                 da.Fill(ds);
    223                 cmd.Parameters.Clear();
    224                 return ds.Tables[0];
    225             }
    226         }
    227 
    228         /// <summary>
    229         /// 将参数集合添加到缓存
    230         /// </summary>
    231         /// <param name="cacheKey">添加到缓存的变量</param>
    232         /// <param name="cmdParms">一个将要添加到缓存的sql参数集合</param>
    233         public static void CacheParameters(string cacheKey, params SqlParameter[] commandParameters)
    234         {
    235             parmCache[cacheKey] = commandParameters;
    236         }
    237 
    238         /// <summary>
    239         /// 找会缓存参数集合
    240         /// </summary>
    241         /// <param name="cacheKey">用于找回参数的关键字</param>
    242         /// <returns>缓存的参数集合</returns>
    243         public static SqlParameter[] GetCachedParameters(string cacheKey)
    244         {
    245             SqlParameter[] cachedParms = (SqlParameter[])parmCache[cacheKey];
    246 
    247             if (cachedParms == null)
    248                 return null;
    249 
    250             SqlParameter[] clonedParms = new SqlParameter[cachedParms.Length];
    251 
    252             for (int i = 0, j = cachedParms.Length; i < j; i++)
    253                 clonedParms[i] = (SqlParameter)((ICloneable)cachedParms[i]).Clone();
    254 
    255             return clonedParms;
    256         }
    257 
    258         /// <summary>
    259         /// 准备执行一个命令
    260         /// </summary>
    261         /// <param name="cmd">sql命令</param>
    262         /// <param name="conn">Sql连接</param>
    263         /// <param name="trans">Sql事务</param>
    264         /// <param name="cmdType">命令类型例如 存储过程或者文本</param>
    265         /// <param name="cmdText">命令文本,例如:Select * from Products</param>
    266         /// <param name="cmdParms">执行命令的参数</param>
    267         private static void PrepareCommand(SqlCommand cmd, SqlConnection conn, SqlTransaction trans, CommandType cmdType, string cmdText, SqlParameter[] cmdParms)
    268         {
    269 
    270             if (conn.State != ConnectionState.Open)
    271             {
    272                 conn.Open();
    273             }
    274             cmd.Connection = conn;
    275             cmd.CommandText = cmdText;
    276             if (trans != null)
    277             {
    278                 cmd.Transaction = trans;
    279             }
    280             cmd.CommandType = cmdType;
    281             if (cmdParms != null)
    282             {
    283                 foreach (SqlParameter parm in cmdParms)
    284                 {
    285                     if ((parm.Value == null) || (string.IsNullOrEmpty(parm.Value.ToString())))
    286                     {
    287                         parm.Value = DBNull.Value;
    288                     }
    289                     cmd.Parameters.Add(parm);
    290                 }
    291             }
    292         }
    293     }
    294 }
      1 using System;
      2 using System.Collections.Generic;
      3 using System.Reflection;
      4 using System.Linq;
      5 using System.Text;
      6 using System.Configuration;
      7 using System.Runtime.Caching;
      8 using System.Data;
      9 using System.Data.SqlClient;
     10 using System.ComponentModel;
     11 using System.ComponentModel.DataAnnotations;
     12 using EasyFast.Utility.CacheUtility;
     13 
     14 namespace EasyFast.Repository
     15 {
     16     public class ModelHelper<T>
     17     {
     18         private string prefix = ConfigurationManager.AppSettings["Prefix"];
     19 
     20         #region 表名、主键与TimeStamp
     21         //数据库表名称
     22         public string TableName
     23         {
     24             get
     25             {
     26                 return prefix + typeof(T).Name; 
     27             }
     28             set
     29             {
     30                 TableName = value;
     31             }
     32         }
     33 
     34         //表主键
     35         public string PrimaryKey
     36         {
     37             get
     38             {
     39                 return GetPropertyInfo().First().Name;
     40             }
     41         }
     42 
     43         public string ModelGuid
     44         {
     45             get
     46             {
     47                 return GetPropertyInfo()[1].Name;
     48             }
     49         }
     50 
     51         //TimeStamp键
     52         public string TimeStamp
     53         {
     54             get
     55             {
     56                 return GetPropertyInfo().Last().Name;
     57             }
     58         }
     59         #endregion
     60 
     61         /// <summary>
     62         /// 从缓存中获取泛型类的PropertyInfo数组,如缓存失效,则创建新的缓存
     63         /// </summary>
     64         /// <returns></returns>
     65         public PropertyInfo[] GetPropertyInfo()
     66         {
     67             PropertyInfo[] infos;
     68             ObjectCache cache = MemoryCache.Default;
     69             string cacheKey = TableName + "_PropertyInfo";
     70             if (EasyFastCache.GetInstance().GetCache(cacheKey) == null)
     71             {
     72                 infos = typeof(T).GetProperties();
     73                 EasyFastCache.GetInstance().AddObjectForever(cacheKey, infos);
     74             }
     75             else
     76             {
     77                 infos = (PropertyInfo[])EasyFastCache.GetInstance().GetCache(cacheKey);
     78             }
     79             return infos;
     80         }
     81 
     82         public SqlParameter GetSqlParameter(PropertyInfo pi,T model)
     83         {
     84             SqlParameter parameter;
     85             switch (pi.PropertyType.Name)
     86             {
     87                 case "String":
     88                     int length = 0;
     89                     object[] attributes = pi.GetCustomAttributes(typeof(StringLengthAttribute), true);
     90                     if (attributes != null && attributes.Length > 0)
     91                     {
     92                         StringLengthAttribute myAttribute = attributes[0] as StringLengthAttribute;
     93                         if (myAttribute != null)
     94                         {
     95                             length = myAttribute.MaximumLength;
     96                         }
     97                     }
     98                     if (length != 0)
     99                     {
    100                         parameter = new SqlParameter("@" + pi.Name, SqlDbType.NVarChar, length);
    101                     }
    102                     else
    103                     {
    104                         parameter = new SqlParameter("@" + pi.Name, SqlDbType.NVarChar);
    105                     }
    106                     parameter.Value = pi.GetValue(model, null);
    107                     break;
    108                 case "Int32":
    109                     parameter = new SqlParameter("@" + pi.Name, SqlDbType.Int, 4);
    110                     parameter.Value = pi.GetValue(model, null);
    111                     break;
    112                 case "Int64":
    113                     parameter = new SqlParameter("@" + pi.Name, SqlDbType.BigInt, 8);
    114                     parameter.Value = pi.GetValue(model, null);
    115                     break;
    116                 case "DataTime":
    117                     parameter = new SqlParameter("@" + pi.Name, SqlDbType.DateTime, 8);
    118                     parameter.Value = pi.GetValue(model, null);
    119                     break;
    120                 case "Boolean":
    121                     parameter = new SqlParameter("@" + pi.Name, SqlDbType.Bit, 2);
    122                     parameter.Value = pi.GetValue(model, null);
    123                     break;
    124                 case "Guid":
    125                     parameter = new SqlParameter("@" + pi.Name, SqlDbType.UniqueIdentifier, 16);
    126                     parameter.Value = pi.GetValue(model, null);
    127                     break;
    128                 case "Byte":
    129                     parameter = new SqlParameter("@" + pi.Name, SqlDbType.Timestamp, 8);
    130                     parameter.Value = pi.GetValue(model, null);
    131                     break;
    132                 default:
    133                     parameter = new SqlParameter("@" + pi.Name, pi.GetValue(model, null));
    134                     break;
    135             }
    136             return parameter;
    137         }
    138     }
    139 }
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Data;
     6 using System.Runtime.Caching;
     7 
     8 namespace EasyFast.Utility.CacheUtility
     9 {
    10     public class EasyFastCache
    11     {
    12         private static object lockHelper = new object();
    13         private static EasyFastCache instance = null;
    14 
    15         private EasyFastCache() { }
    16 
    17         public static EasyFastCache GetInstance()
    18         {
    19             if (instance == null)
    20             {
    21                 lock (lockHelper)
    22                 {
    23                     if (instance == null)
    24                     {
    25                         instance = new EasyFastCache();
    26                     }
    27                 }
    28             }
    29             return instance;
    30         }
    31 
    32         /// <summary>
    33         /// 添加一个对象到缓存中,如30分钟未访问,则删除该缓存项
    34         /// </summary>
    35         /// <param name="name">该缓存项的唯一标识符</param>
    36         /// <param name="obj">要插入的对象。</param>
    37         public void AddObject(string name, Object dt)
    38         {
    39             ObjectCache cache = MemoryCache.Default;
    40             CacheItemPolicy policy = new CacheItemPolicy();
    41             policy.SlidingExpiration = TimeSpan.FromMinutes(30);
    42             cache.Set(name, dt, policy);
    43         }
    44 
    45         /// <summary>
    46         /// 添加一个对象到缓存中,该对象拥有最高优先级,永不被删除
    47         /// </summary>
    48         /// <param name="name">该缓存项的唯一标识符</param>
    49         /// <param name="obj">要插入的对象。</param>
    50         public void AddObjectForever(string name, Object obj)
    51         {
    52             ObjectCache cache = MemoryCache.Default;
    53             CacheItemPolicy policy = new CacheItemPolicy();
    54             policy.Priority = CacheItemPriority.NotRemovable;
    55             cache.Set(name, obj, policy);
    56         }
    57 
    58         /// <summary>
    59         /// 添加一个DataTable到缓存中,并且依赖于数据库过期策略,该方法只支持SQL2005及以上
    60         /// </summary>
    61         /// <param name="name">该缓存项的唯一标识符</param>
    62         /// <param name="dt">要插入的DataTable</param>
    63         /// <param name="sm">数据库依赖监控对象</param>
    64         public void AddObject(string name, DataTable dt, SqlChangeMonitor sm)
    65         {
    66             ObjectCache cache = MemoryCache.Default;
    67             CacheItemPolicy policy = new CacheItemPolicy();
    68             policy.ChangeMonitors.Add(sm);
    69             cache.Set(name, dt, policy);
    70         }
    71 
    72         /// <summary>
    73         /// 获取指定标识符的缓存项
    74         /// </summary>
    75         /// <param name="cacheKey">该缓存项的唯一标识符</param>
    76         /// <returns>该缓存</returns>
    77         public object GetCache(string cacheKey)
    78         {
    79             ObjectCache cache = MemoryCache.Default;
    80             return cache[cacheKey];
    81         }
    82     }
    83 }

    本节代码下载:EasyFastCMS-2014.05.30.zip

  • 相关阅读:
    Docker的历史
    IP路由基础
    Docker的基础知识(二)
    Docker的基础知识(一)
    CentOS7下安装部署“zabbix”
    使用amoeba实现mysql读写分离
    ?? 运算符(C# 参考)
    ?? 运算符(C# 参考)
    knockout,change事件
    knockout,change事件
  • 原文地址:https://www.cnblogs.com/cnuusw/p/EasyFast_2.html
Copyright © 2020-2023  润新知