一般在N层设计中,数据层绝不应该牵扯到逻辑.理由很多,但最重要的一点,应该是有利于维护.如果面向的数据库是无存储过程的,那么这个法则应该被遵守.比如ACCESS,MYSQL.
如果使用MS SQLServer等其它有储存过程的数据库,我个人认为大不必如此.有时候一个好的存储过程能带来更良好的性能合可读性.
经典的架构就和牛顿的经典力学一样,并不是放之四海而皆为准的,不用毛主席的话说,那就是没有银弹.架构,OOP,这些前辈的经验都是面对一个问题的——客户的需求要变。如果客户的需求不变动,那要OOP,要设计模式,要架构有什么用?面向过程完全能写出更加高效,更加大众化的程序来。
我认为带逻辑的存储过程完全是AOP的实例,虽然存储过程不具备OOP的特征。数据层用来提供数据,至于怎么提供数据我认为没有必要过于关心。虽然一个带逻辑的存储过程可能会进行很多操作,以至于耦合度太高。但可以认为它是一个方法,甚至可以理解为一个封装的组件。
比如,在项目实施中实现站内短信息系统。当然,我这个例子可能不够好。
站内短消息要实现站内短信息的发送,收取,群发,黑名单过滤功能,涉及到批量更新数据及过滤。
建立3个表:
1,Messages
(MessagesID,UserFromID,Subject,[Content],SendToCount,IsKilledBySender)
分别是 ID,用户ID,主题,内容,发送数量,是否被发件人删除 //我在这里做了适当简化
2. MessagesToUsers
(MessageID,UserID,IsReaded)
分贝是ID,用户ID,是否已读
3. BlackList
(ListID,UserOwner,UserTarget)
分别是 ID,屏蔽的用户,被屏蔽的用户
要发送一次群发,如果用ADO.NET处理,需要以下步骤
1. 连接数据库;
2. 查询获得收件人的ID; //用户发送是选或填写用户名列表,需要遍历数据库对应ID
3. 插入消息; //把消息写入Messages
4. 以收件人数开始循环; //把收件人和信息得关系写入MessagesToUsers,是1对多关系
5. 循环中读取黑名单查看该发件人是否被收件人屏蔽;
6. 如果屏蔽则返回循环
7. 如果没屏蔽, 插入消息与收件人关系
这样就实现了.看上去复杂,却是最简单,最容易想到的办法.
而这个算法无疑使效率变得非常低.
而可以使用以下储存过程代替
1
set
ANSI_NULLS
ON
2
set
QUOTED_IDENTIFIER
ON
3
GO
4
--
=============================================
5
--
Author: <Author,,Name>
6
--
Create date: <Create Date,,>
7
--
Description: <Description,,>
8
--
=============================================
9
ALTER
PROCEDURE
[
dbo
]
.
[
SendMessages
]
10
(
11
@subject
nvarchar
(
200
),
--
主题
12
@content
text
,
--
内容
13
@sendto
nvarchar
(
2000
),
--
收件人列表,以,分割的字符
14
@from
int
,
--
发件人
15
@type
bit
--
消息类型(0为用户消息,1为系统提醒)
16
)
17
AS
18
BEGIN
19
SET
NOCOUNT
ON
;
20
--
插入消息
21
insert
into
InMessages (UserFromID,Subject,
[
Content
]
,SendTime,IsKilledBySender,ReadCount,SendToCount,MessageType)
22
values
(
@from
,
@subject
,
@content
,
getDate
(),
0
,
0
,
0
,
@type
);
23
--
取得插入消息ID
24
declare
@messageid
int
25
set
@messageid
=
@@IDENTITY
26
--
构造虚拟表(在查询用户ID的基础上,添加自定字段)
27
declare
@sql
nvarchar
(
400
)
28
set
@sql
=
'
select MessageID=
'
+
cast
(
@@IDENTITY
as
varchar
)
+
'
,UserID,IsReaded=0 from Users where DisplayName in (
'
+
@sendto
+
'
) and (select count(UserTarget) from MsgBlackList where UserOwner = UserID and UserTarget =
'
+
cast
(
@from
as
varchar
)
+
'
) = 0
'
29
insert
into
InMessagesToUsers
EXEC
(
@sql
)
30
31
--
更新该邮件发送人数
32
declare
@sendcount
int
33
set
@sendcount
=
(
select
count
(mu.MessageID)
from
InMessagesToUsers
as
mu
where
mu.MessageID
=
@messageid
)
34
update
InMessages
set
SendToCount
=
@sendcount
where
MessageID
=
@messageid
35
36
--
返回邮件发送人数,表字段名:SendCount
37
select
SendCount
=
@sendcount
38
END
39
40
传入参数里有得字段被我省略了(SQL Server 2005).
发送人发送消息被记录到InMessages 表
收件人由字符串组成,所以查询采用select in
收件人于信件的关系被记录在表InMessagesToUsers 表
黑名单表MsgBlackList
而调用也非常简单
1
///
<summary>
2
///
执行存储过程SendMessages
3
///
</summary>
4
///
<returns></returns>
5
public
override
string
ProcessAction()
6
{
7
string
subject
=
GetQueryValue(
"
Subject
"
);
8
string
content
=
GetQueryValue(
"
Content
"
);
9
string
sendto
=
GetQueryValue(
"
SendTo
"
);
10
sendto
=
"
'
"
+
sendto
+
"
'
"
;
11
sendto
=
sendto.Replace(
"
,
"
,
"
','
"
); //sendto是有,连接的收件人,这里处理了才能被select in 使用
12
13
SUser s
=
LoginHelper.CrrentUser();
14
int
from
=
s.UserID;
15
16
if
(from
!=
0
)
17
{
18
bool
MessageType
=
false
;
19
SqlParameter[] parms
=
{
20
new
SqlParameter(
"
@subject
"
,SqlDbType.NVarChar,
200
),
21
new
SqlParameter(
"
@content
"
,SqlDbType.Text),
22
new
SqlParameter(
"
@sendto
"
,SqlDbType.NVarChar,
4000
),
23
new
SqlParameter(
"
@from
"
,SqlDbType.Int),
24
new
SqlParameter(
"
@type
"
,SqlDbType.Bit)
25
};
26
parms[
0
].Value
=
subject;
27
parms[
1
].Value
=
content;
28
parms[
2
].Value
=
sendto;
29
parms[
3
].Value
=
from;
30
parms[
4
].Value
=
MessageType;
31
32
33
DataTable dt
=
DBHelper.ExecuteTable
34
(
35
CommandType.StoredProcedure,
36
"
SendMessages
"
,
37
parms
38
);
39
40
//
sendcount应为INT类型,这里用string用于返回
41
string
sendcount
=
dt.Rows[
0
][
"
SendCount
"
].ToString();
42
43
return
"
2|消息共发送给了
"
+
sendcount
+
"
人|SendMessages.aspx
"
;
44
45
}
46
else
47
{
48
return
"
2|请登陆后再发|Login.aspx
"
;
49
}
50
}
51
}
无论效率和可读性都比常规办法要好很多.
存储过程SendMessages可以理解为一个黑箱子.处理完返回实际发送给了多少人.
http://www.cnblogs.com/birdshover/
2007年1月25日