最近,一直在学习和摸索关于项目架构的东东。或许说架构说得有点太大。但是还是暂且用着吧。
也看看过几个高手关于三层架构和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直接生成,所以我想在这层中应该是相当的成熟了。所以很想知道那些比较优良的解决方案。