从本节课开始,我们开始逐步正式进入实际的编码过程中。本节课的核心内容为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