最近,一直在学习和摸索关于项目架构的东东。或许说架构说得有点太大。但是还是暂且用着吧。 也看看过几个高手关于三层架构和MVC模型的文章,觉得很多东西的理解和自己的不是很一样。但是自己确实没有他们研究的深入,所以也不妄加评论。 在这里想说的是,自己幼稚的观点欢迎各位砸砖;自己绝对的言语只是针对自己的想法。 我不是什么大虾,所以肯定没有架子,不会跟别人撑死争执,只会死缠着问。 一、数据库设计的角度来说。个人的观点是数据库的设计应该是完全的面向需求和性能。而不应该考虑或是只是适当考虑代码设计的问题。 表结构对程序的设计是有相当大的影响的。但是我们的表是根据需求来做的,同时考虑将来访问的性能问题。视图某种程度上是表 的延伸,但是他依赖表的设计。存储过程是业务逻辑一定程度上原始的表达。 总结:数据库设计中对系统架构设计颇有影响的就是:表,视图,存储过程 其他的,比如约束,索引主要是维持表的完整性和提高数据读取的性能,对系统的结构影响甚微。 恕我无知,我在做数据库设计是一般就是用到这么几个元素,其中索引用之很少。 我是坚定的存储过程派(如果分派的话),在这里不去讨论两派的论战了。但是对存储过程的使用也是相当的有疑惑: 1.存储过程抽空了业务逻辑的功能,让业务逻辑名存实亡; 2.存储过程加大了数据与UI的耦合度(呵呵,不知道自己对耦合的理解对否?) 3.项目中存储过程泛滥(很简单的SQL写成了存储过程,很多功能相似的存储过程) 4.对于3采用动态存储过程,就出现耦合严重 二、数据库访问层 1. 看过好几个项目,看到别人的做法总是不厌其烦的用add方法向存储过程添加参数的时候,就在怀疑自己的做法是不很好。 我想为什么不做出一个通用的方法呢? 代码如下:
1using System; 2using System.Data; 3using System.Data.SqlClient; 4 5namespace DB.Componse 6{ 7 /**//// <summary> 8 ///基于SqlCilent的数据操作基类(全存储过程实现) 9 /// </summary> 10 public class SqlProcedure :IDisposable 11 { 12 构造和声明#region 构造和声明 13 /**//// <summary> 14 /// 构造函数 15 /// </summary> 16 public SqlProcedure() 17 { 18 } 19 /**//// <summary> 20 /// 重构构造函数 21 /// 带有参数ConnStr(表示连接字符串) 22 /// </summary> 23 public SqlProcedure(string ConnStr) 24 { 25 this.ConnStr = ConnStr; 26 // this.ConnOpen();数据库连接打开不必过早 27 } 28 /**//// <summary> 29 /// 析构函数 30 /// </summary> 31 ~SqlProcedure() 32 { 33 this.ConnClose(); 34 this.Dispose(); 35 } 36 /**//// <summary> 37 /// 打开数据库连接 38 /// </summary> 39 private void ConnOpen() 40 { 41 if (Conn == null) 42 { 43 //实例化数据库连接对象 44 Conn = new SqlConnection(ConnStr); 45 Conn.Open(); 46 } 47 } 48 /**//// <summary> 49 /// 关闭数据库连接 50 /// </summary> 51 private void ConnClose() 52 { 53 if (Conn != null) 54 { 55 Conn.Close(); 56 } 57 } 58 /**//// <summary> 59 /// 释放数据库连接对象的资源 60 /// </summary> 61 public void Dispose() 62 { 63 if (Conn != null) 64 { 65 Conn.Dispose(); 66 Conn = null; 67 } 68 } 69 /**//// <summary> 70 /// ConnStr:数据库连接字符串(私有字段) 71 /// Conn:数据库连接对象(私有对象) 72 /// </summary> 73 private string ConnStr; 74 private SqlConnection Conn; 75 #endregion 76 77 数据库Command对象及参数对象的创建#region 数据库Command对象及参数对象的创建 78 /**//// <summary> 79 /// 创建一个依赖存储过程的Command对象(私有化) 80 /// </summary> 81 /// <param name="ProcName">欲调用的存储过程名</param> 82 /// <param name="Params">调用存储过程所需的参数集</param> 83 /// <returns>一个可使用的Command对象</returns> 84 private SqlCommand CreateComm(string ProcName,SqlParameter[] Params) 85 { 86 //创建Command对象 87 this.ConnOpen(); 88 SqlCommand Comm = new SqlCommand(ProcName,Conn); 89 Comm.CommandType = CommandType.StoredProcedure; 90 91 //为其添加参数 92 if (Params!=null) 93 { 94 foreach (SqlParameter temp in Params) 95 { 96 Comm.Parameters.Add(temp); 97 } 98 Comm.Parameters.Add(new SqlParameter 99 ("ReturnValue", SqlDbType.Int, 4, ParameterDirection.ReturnValue, false, 0, 0, 100 String.Empty, DataRowVersion.Default, null)); 101 } 102 return Comm; 103 } 104 /**//// <summary> 105 /// 参数构造的基本方法(私有化) 106 /// </summary> 107 /// <param name="ParamName">参数名</param> 108 /// <param name="dbType">参数在数据库中的类型</param> 109 /// <param name="size">参数设置的最大大小</param> 110 /// <param name="Value">参数的值(object类型)</param> 111 /// <param name="direction">参数方向</param> 112 /// <returns>参数对象</returns> 113 private SqlParameter MakeParam(string ParamName,SqlDbType dbType,int size,object Value,ParameterDirection direction) 114 { 115 SqlParameter Param = new SqlParameter(ParamName, dbType); 116 if (size > 0) 117 { 118 Param.Size = size; 119 } 120 Param.Direction = direction; 121 if (!(Value==null&&direction==ParameterDirection.Output)) 122 { 123 Param.Value = Value; 124 } 125 return Param; 126 } 127 /**//// <summary> 128 /// 公开的传入参数方法 129 /// </summary> 130 /// <param name="ParamName">参数名</param> 131 /// <param name="dbType">参数在数据库中的类型</param> 132 /// <param name="size">参数设置的最大大小</param> 133 /// <param name="Value">参数的值</param> 134 /// <returns>参数对象</returns> 135 public SqlParameter MakeInParam(string ParamName, SqlDbType dbType, int size, object Value) 136 { 137 return MakeParam(ParamName, dbType, size, Value, ParameterDirection.Input); 138 } 139 /**//// <summary> 140 /// 公开的传出参数方法 141 /// </summary> 142 /// <param name="ParamName">参数名</param> 143 /// <param name="dbType">参数在数据库中的类型</param> 144 /// <param name="size">参数设置的最大大小</param> 145 /// <returns>参数对象</returns> 146 public SqlParameter MakeOutParam(string ParamName, SqlDbType dbType, int size) 147 { 148 return MakeParam(ParamName, dbType, size, null, ParameterDirection.Output); 149 } 150 #endregion 151 152 数据库操作方法#region 数据库操作方法 153 /**//// <summary> 154 /// 运行带参数的存储过程,无数据返回 155 /// </summary> 156 /// <param name="ProcName">存储过程名</param> 157 /// <param name="Params">参数集</param> 158 /// <returns>受影响的行数</returns> 159 public int ProcNonQuery(string ProcName, SqlParameter[] Params) 160 { 161 SqlCommand myComm = CreateComm(ProcName, Params); 162 this.ConnOpen(); 163 int i=myComm.ExecuteNonQuery(); 164 myComm.Parameters.Clear(); 165 this.ConnClose(); 166 //存在index为"ReturnValue"的参数 167 //int i = Convert.ToInt32(myComm.Parameters["ReturnValue"].Value); 168 return i; 169 } 170 /**//// <summary> 171 /// 运行无参数的存储过程,无返回 172 /// </summary> 173 /// <param name="ProcName">存储过程名</param> 174 /// <returns>返回受影响的行数</returns> 175 public int ProcNonQuery(string ProcName) 176 { 177 SqlCommand myComm = CreateComm(ProcName, null); 178 this.ConnOpen(); 179 int i=myComm.ExecuteNonQuery(); 180 this.ConnClose(); 181 //存在index为"ReturnValue"的参数 182 //int i = Convert.ToInt32(myComm.Parameters["ReturnValue"].Value); 183 return i; 184 } 185 /**//// <summary> 186 /// 执行无参存储过程,返回第一行数据 187 /// </summary> 188 /// <param name="ProcName">存储过程名</param> 189 /// <returns>返回一个首行数据对象</returns> 190 public object ProcScalar(string ProcName) 191 { 192 SqlCommand myComm = CreateComm(ProcName, null); 193 this.ConnOpen(); 194 object val = myComm.ExecuteScalar(); 195 this.ConnClose(); 196 return val; 197 } 198 /**//// <summary> 199 /// 执行有参存储过程,返回第一行数据 200 /// </summary> 201 /// <param name="ProcName">存储过程名</param> 202 /// <param name="Params">参数集</param> 203 /// <returns>返回一个首行数据对象</returns> 204 public object ProcScalar(string ProcName, SqlParameter[] Params) 205 { 206 SqlCommand myComm = CreateComm(ProcName, Params); 207 this.ConnOpen(); 208 object val=myComm.ExecuteScalar(); 209 myComm.Parameters.Clear(); 210 this.ConnClose(); 211 return val; 212 } 213 /**//// <summary> 214 /// 运行无参数的存储过程,返回一个DataReader对象数据集 215 /// </summary> 216 /// <param name="ProcName">存储过程名</param> 217 /// <param name="dr">DataReader对象</param> 218 public void ProcReader(string ProcName, out SqlDataReader dr) 219 { 220 SqlCommand myComm = CreateComm(ProcName, null); 221 this.ConnOpen(); 222 dr = myComm.ExecuteReader(CommandBehavior.CloseConnection); 223 } 224 /**//// <summary> 225 /// 运行带参数的存储过程,返回一个DataReader数据集 226 /// </summary> 227 /// <param name="ProcName">存储过程名</param> 228 /// <param name="Params">参数集</param> 229 /// <param name="dr">DataReader数据集</param> 230 public void ProcReader(string ProcName,out SqlDataReader dr, SqlParameter[] Params) 231 { 232 SqlCommand myComm = CreateComm(ProcName, Params); 233 this.ConnOpen(); 234 dr = myComm.ExecuteReader(CommandBehavior.CloseConnection); 235 myComm.Parameters.Clear(); 236 // dr = myComm.ExecuteReader(); 237 //this.ConnClose(); 238 } 239 /**//// <summary> 240 /// 运行带参数的存储过程,返回一个适配器对象DataAdapter 241 /// </summary> 242 /// <param name="ProcName">存储过程名</param> 243 /// <param name="Params">参数集</param> 244 /// <param name="da">适配器对象</param> 245 public void ProcAapter(string ProcName, SqlParameter[] Params, out SqlDataAdapter da) 246 { 247 SqlCommand myComm = CreateComm(ProcName, Params); 248 this.ConnOpen(); 249 SqlDataAdapter sda = new SqlDataAdapter(myComm); 250 myComm.Parameters.Clear(); 251 this.ConnClose(); 252 da = sda; 253 } 254 /**//// <summary> 255 /// 运行无参存储过程,返回适配器对象DataAdapter 256 /// </summary> 257 /// <param name="ProcName">存储过程名</param> 258 /// <param name="da">适配器对象DataAdapter</param> 259 public void ProcAapter(string ProcName, out SqlDataAdapter da) 260 { 261 SqlCommand myComm = CreateComm(ProcName, null); 262 this.ConnOpen(); 263 SqlDataAdapter sda = new SqlDataAdapter(myComm); 264 this.ConnClose(); 265 da = sda; 266 } 267 #endregion 268 } 269} 270 2.看到经典的petshop4.0中,数据库访问层返回的都是DataReader对象,这样确实很好。但是如果我的一个方法中除了要求返回若干数据集,还要返回传出参数,那怎么办呢? (我的做法是在数据库访问层中先将DataReader中的数据转移),这样感觉有点不伦不类了。 3.对于这层,现在大虾的做法是用ORM直接生成,所以我想在这层中应该是相当的成熟了。所以很想知道那些比较优良的解决方案。
|