数据层的逻辑

一般在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日

你可能感兴趣的:(数据)