最近,一直在学习和摸索关于项目架构的东东。或许说架构说得有点太大。但是还是暂且用着吧。
也看看过几个高手关于三层架构和MVC模型的文章,觉得很多东西的理解和自己的不是很一样。但是自己确实没有他们研究的深入,所以也不妄加评论。
在这里想说的是,自己幼稚的观点欢迎各位砸砖;自己绝对的言语只是针对自己的想法。
我不是什么大虾,所以肯定没有架子,不会跟别人撑死争执,只会死缠着问。
一、数据库设计的角度来说。个人的观点是数据库的设计应该是完全的面向需求和性能。而不应该考虑或是只是适当考虑代码设计的问题。
表结构对程序的设计是有相当大的影响的。但是我们的表是根据需求来做的,同时考虑将来访问的性能问题。视图某种程度上是表 的延伸,但是他依赖表的设计。存储过程是业务逻辑一定程度上原始的表达。
总结:数据库设计中对系统架构设计颇有影响的就是:表,视图,存储过程
其他的,比如约束,索引主要是维持表的完整性和提高数据读取的性能,对系统的结构影响甚微。
恕我无知,我在做数据库设计是一般就是用到这么几个元素,其中索引用之很少。
我是坚定的存储过程派(如果分派的话),在这里不去讨论两派的论战了。但是对存储过程的使用也是相当的有疑惑:
1.存储过程抽空了业务逻辑的功能,让业务逻辑名存实亡;
2.存储过程加大了数据与UI的耦合度(呵呵,不知道自己对耦合的理解对否?)
3.项目中存储过程泛滥(很简单的SQL写成了存储过程,很多功能相似的存储过程)
4.对于3采用动态存储过程,就出现耦合严重
二、数据库访问层
1. 看过好几个项目,看到别人的做法总是不厌其烦的用add方法向存储过程添加参数的时候,就在怀疑自己的做法是不很好。
我想为什么不做出一个通用的方法呢?
代码如下:
1
using System;
2
using System.Data;
3
using System.Data.SqlClient;
4
5
namespace 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&&directinotallow==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直接生成,所以我想在这层中应该是相当的成熟了。所以很想知道那些比较优良的解决方案。