GridView&ObjectDataSource新特性小记 懒人篇

"懒"序;
         Visual Studio 2005推广的时间不算短了,它为我们带来的很多新特性使得开发更加高效和有趣.相信众多VS开发者抢鲜体验过并为此激动不已了.不论是IDE的格局还是 FrameWork的改进,都十分令人赏心悦目.在微软公布的诸多新特性里面,最为让我关注的部分,就是数据绑定.有过经验的朋友一定知道,在 FrameWork1.0甚至更早时期的版本,数据绑定控件和数据源提供的可选功能相当薄弱,为实现一个较为复杂的数据显示或操作需要而coding,都 是一件颇为恐怖的事情.VS2003中的DataGrid曾凭借其良好的功能集成,与SqlDataSource配合,为我们减轻了一定的负担,一直成为 数据绑定的首选.虽然它提供了相应的事件接口,但仍需要大量的代码才得以完成.微软的产品一向是助长开发者们的惰性的.自VS2005推出以来, GridView作为DataGrid不二的继承人,逐渐显露它的强大,慢慢为像我们这样的懒人接受并打算长期使用.加上有FrameWork2.0新品 ObjectDatasource的无缝支持,它俩简直就是数据绑定界天造地设的一对,使用非常省心,就一个词:"Perfection"...

"懒"归正传:
         最近开场废话是多了点(可能是参加会议太多闹的.. ^_^!!).马上请出GridView & ObjectDataSource.
下面我将逐步展现一个分页的案例.

案例环境: WindowsXP SP2, VS2005 Team Suite,SqlServer2005(没有比这更糟的了....)
要求:         了解数据绑定控件的结构,数据源的运行机制,以及简单的绑定控件设计实现(那些内容足够再写一篇教程了,这里不再多叙.)
参 考:         MSDN中提到,ObjectDataSource是唯一支持界面分页的数据源(除非自己来继承造一个,汗!),但示例仍    然是用SqlDataSource做数据源介绍的GirdView绑定.难道MS这么小气???(ps:打死俺也不说).

那好,就从那句介绍开始,咱们自己动手整出一个来.
按照常规,先准备一张表和一些存储过程,如下:

 

Table :MyUsers 
     UserID (
int , primary   key , identity )   -- 自动增加字段,用户ID标识列
     UserName ( nvarchar ( 50 ), not   null )    -- 用户名
     Description ( nvarchar ( 50 ), not   null ) -- 备注

Procedure :

CREATE   PROCEDURE   [ dbo ] . [ AddUser ]   -- 增加一个用户
     @UserName   nvarchar ( 50 ),
    
@Description   nvarchar ( 50 )
AS
BEGIN
    
SET  NOCOUNT  ON ;

    
begin   transaction  t
    
    
insert   into  MyUsers(UserName,Description) 
    
values ( @UserName , @Description )
    
    
if   @@error   <>   0
    
begin  
        
rollback   transaction  t
    
end
    
else
    
begin  
        
commit   transaction
    
end
END

CREATE   PROCEDURE   [ dbo ] . [ DeleteUserByUserID ]    -- 删除一个用户
     @UserID   int
AS
BEGIN
    
SET  NOCOUNT  ON ;

    
Begin   Transaction  t

    
delete   from  MyUsers  where  UserID  = @UserID

    
if   @@error   <>   0
        
begin  
            
rollback   transaction  t
        
end  
    
else
        
begin
            
commit   transaction
        
end     
END

CREATE   PROCEDURE   [ dbo ] . [ UpdateUser ]   -- 修改用户姓名或备注
     @UserID   int ,
    
@UserName   nvarchar ( 50 ),
    
@Description   nvarchar ( 50 )
AS
BEGIN
    
SET  NOCOUNT  ON ;

    
begin   transaction  t
    
    
update  MyUsers 
    
set  UserName  =   @UserName ,
        Description 
=   @Description  
    
where  UserID  =   @UserID

    
if   @@error   <>   0  
        
begin
            
rollback   transaction  t
        
end
    
else
        
begin
            
commit   transaction   t
        
end
END

CREATE   PROCEDURE   [ dbo ] . [ GetUsers ]   -- 得到用户列表,注意这里的参数
     @RowIndex   int ,
    
@RecordCount   int
AS
BEGIN
    
SET  NOCOUNT  ON ;

    
With  VUsers  as  (
        
select   * ,row_number()  over  ( order   by  UserID  desc as  RowNum
        
from  MyUsers 
)

    
select   *   from  VUsers 
    
where  RowNum  >   @RowIndex   and  RowNum  <=  ( @RowIndex + @RecordCount )    
END

CREATE   PROCEDURE   [ dbo ] . [ GetUsersCount ]     
AS
BEGIN
    
SET  NOCOUNT  ON ;
    
select   count (UserID)  from  MyUsers
END


这里详细说明一下倒数两个存储过程,GetUsers的参数RowIndex,不是页码(传说中的PageIndex),而是行索引,且从 0开始.这点特别要注意,因为要让ObjectDataSource自动取得当前需要的数据(界面级分页意味着当前需要显示多少数据只向数据库取多少,并 不会像其他数据源全总取出消耗性能.),依据也就是行索引和增量.GetUsersCount这个存储过程是为ObjectDataSource分页提供 总数的,它与分页的存储过程要保持一致.特别指的是有分页条件的情况,本人经常忘记(^_^||).否则GridView显示会不正常.

在WebSite新建一个DAL,假定类名为DataManager,给出代码片段如下:

 

using  System;
using  System.Data;
using  System.Data.SqlClient;
using  System.Configuration;
using  System.Web;
using  System.Web.Security;
using  System.Web.UI;
using  System.Web.UI.WebControls;
using  System.Web.UI.WebControls.WebParts;
using  System.Web.UI.HtmlControls;
using  System.Collections;
using  System.Collections.Generic;

/// <summary>
/// DataAccessLayer
/// </summary>

public   class  DataManager
{
    
private SqlConnection con = null//连接对象
    private SqlCommand cmd = null;  //command执行对象
    private SqlDataAdapter da = null//适配器对象

    
/// <summary>
    
/// DAL对象构造
    
/// </summary>

    public DataManager()
    
{
        
//
        
// TODO: Add constructor logic here
        
//
    }


    
/// <summary>
    
/// 打开数据库连接
    
/// </summary>

    private void OpenConnection()
    
{
        
try
        
{
            
string conString = ConfigurationManager.ConnectionStrings["localDB"].ConnectionString;
            con 
= new SqlConnection(conString);
            
if (ConnectionState.Closed == con.State)
            
{
                con.Open();                    
            }

        }

        
catch (SqlException ex)
        
{
            
throw new Exception("数据库无法访问", ex);
        }

    }


    
/// <summary>
    
/// 关闭数据库连接
    
/// </summary>

    private void CloseConnection()
    
{
        
if (ConnectionState.Open == con.State)
        
{
            
try
            
{
                con.Close();
            }

            
catch (SqlException ex)
            
{
                
throw new Exception("数据库无法关闭", ex);
            }

        }

    }


    
/// <summary>
    
/// 取得用户列表
    
/// </summary>
    
/// <param name="rowIndex">行索引</param>
    
/// <param name="recordCount">页显示量(增量)</param>
    
/// <returns>用户列表数据集</returns>

    public DataSet GetUsers(int rowIndex, int recordCount)
    
{
        OpenConnection();
        
try
        
{
            cmd 
= new SqlCommand();
            cmd.Connection 
= con;
            cmd.CommandType 
= CommandType.StoredProcedure;
            cmd.CommandText 
= "GetUsers";
            
            SqlParameter spRowIndex 
= new SqlParameter("@RowIndex",SqlDbType.Int,4);
            spRowIndex.Direction 
= ParameterDirection.Input;        
            SqlParameter spRecordCount 
= new SqlParameter("@RecordCount",SqlDbType.Int,4);
            spRecordCount.Direction 
= ParameterDirection.Input;

            cmd.Parameters.Add(spRowIndex);
            cmd.Parameters.Add(spRecordCount);

            spRowIndex.Value 
= rowIndex;
            spRecordCount.Value 
= recordCount;

            da 
= new SqlDataAdapter(cmd);
            DataSet ds 
= new DataSet();
        
            da.Fill(ds, 
"MyUsers");

            
return ds;           
        }

        
catch (SqlException ex)
        
{
            
throw new Exception("无法取得有效数据", ex);
        }

        
finally
        
{
            CloseConnection();
        }

    }


    
/// <summary>
    
/// 取得用户总数
    
/// </summary>
    
/// <returns>用户总数</returns>

    public int GetUsersCount()
    
{
        OpenConnection();
        
try
        
{
            cmd 
= new SqlCommand();
            cmd.Connection 
= con;
            cmd.CommandType 
= CommandType.StoredProcedure;
            cmd.CommandText 
= "GetUsersCount";
            
int count = Convert.ToInt32(cmd.ExecuteScalar().ToString());
            
return count;
        }

        
catch (SqlException ex)
        
{
            
throw new Exception("无法取得有效数据", ex);
        }

        
finally
        
{
            CloseConnection();
        }

    }

 

对DAL也有几项说明,DataManager.GetUsers(int rowIndex, int recordCount)方法的参数只能有两个,
参数名可以随意,但意义却要与调用的存储过程GetUsers要一致,rowIndex必须是行索引,recordCount必须是页显示量.
OK!接下来在页面上放上一个GridView和一个ObjectDataSource,设置代码片段如下:


< asp:GridView  ID ="gvMyUsers"  runat ="server"  AllowPaging ="True"  CellPadding ="4"  DataSourceID ="objMyUsers"  ForeColor ="#333333"  GridLines ="None"  AutoGenerateDeleteButton ="True"  AutoGenerateEditButton ="True"  AutoGenerateColumns ="False"  DataKeyNames ="UserID"  PageSize ="10" >
< FooterStyle  BackColor ="#507CD1"  Font-Bold ="True"  ForeColor ="White"   />
< RowStyle  BackColor ="#EFF3FB"   />
< EditRowStyle  BackColor ="#2461BF"   />
< SelectedRowStyle  BackColor ="#D1DDF1"  Font-Bold ="True"  ForeColor ="#333333"   />
< PagerStyle  BackColor ="#2461BF"  ForeColor ="White"  HorizontalAlign ="Center"   />
< HeaderStyle  BackColor ="#507CD1"  Font-Bold ="True"  ForeColor ="White"   />
< AlternatingRowStyle  BackColor ="White"   />
</ asp:GridView >     
< asp:ObjectDataSource  ID ="objMyUsers"  runat ="server"  EnablePaging ="True"  MaximumRowsParameterName ="recordCount"  
SelectCountMethod
="GetUsersCount"  SelectMethod ="GetUsers"  StartRowIndexParameterName ="rowIndex"  TypeName ="DataManager" >
</ asp:ObjectDataSource >

指定每页显示最大数据量(页显示量)的参数:
MaximumRowsParameterName="recordCount"
指定取得数据总数方法:
SelectCountMethod="GetUsersCount"
指定分页方法:
SelectMethod="GetUsers"
指定起始行参数:
StartRowIndexParameterName="rowIndex"
指定前面方法所属类名(全限定名):
TypeName="DataManager
这几个设置是必须的,一定要对应.

现在轻轻的点击一下运行吧(什么什么?还没写事件?...我说老铁,都啥年月了,懒人还有用那玩儿吗?).到这里,一个最快速的分页其实已经做完了.

前面的步骤都是必须的,但仍然可以有一些变化.比如,若你已经按以往的办法写好了一个类似于

Create   Procedure  GetUsers
    
@PageIndex   int ,
    
@PageSize   int
as
begin
    
end
        这样的存储过程了,没关系,你在DAL的DataManager.GetUsers(int rowIndex, int recordCount)这里,
把rowIndex,recordCount在调用存储过程前转换成PageIndex,PageSize就好了,也不过是
PageIndex = rowIndex/recordCount +1; PageSize =recordCount;这样的语句就能搞定啦.再或者改存储过程里面也行(虽然有点不值得),不多说了.自己耍一把就知道了.
        你一定心里还有疑问,没错,DataManager.GetUsers(int rowIndex, int recordCount)这个方法,更多时候需要多一些参数,也就是说,我们分页取数据的过程,还需要一些筛选条件,但这个方法是要给 ObjectDataSource的selectMethod方法,不能增加别的参数,形成矛盾怎么办??欲知解决之道,且等下回分解.....(快跑 啊.....鸡蛋来啦!!)

        书接上回,我们提到,如果我们分页的数据,在查询的存储过程中需要更多参数,在使用ObjectDataSource作为数据源完成界面级分页,我们必须 做一些其他的事情.为了让示例更为易懂,我们将上一次的MyUsers表变化一下,增加一个用户状态列.并增加两个存储过程.

Table : MyUsers
  
@UserID  ( int , primary   key , identity ),
  
@UserName  ( nvarchar ( 50 ), not   null ),
  
@Description  ( nvarchar ( 50 ), not   null ),
  
@Status  ( bit , not   null )

Procedure :
  
create   procedure   [ dbo ] . [ GetUsersByStatus ]    -- 通过状态得到用户列表
     @RowIndex   int ,
    
@RecordCount   int ,
    
@Status   bit
AS
BEGIN
    
SET  NOCOUNT  ON ;

    
With  VUsers  as  (
        
select   * ,row_number()  over  ( order   by  UserID  desc as  RowNum
        
from  MyUsers  where  Status  =   @Status
)

    
select   *   from  VUsers 
    
where  RowNum  >   @RowIndex   and  RowNum  <=  ( @RowIndex + @RecordCount )    
END

CREATE   PROCEDURE   [ dbo ] . [ GetUsersCountByStatus ]    -- 取得通过状态得到用户列表的总数
     @Status   bit
AS
BEGIN
    
SET  NOCOUNT  ON ;
    
select   count (UserID)  from  MyUsers  where  Status  =   @Status
END

        在WebSite的DataManager中,再增加两个带参数的分页查询的方法.下面介绍两种带参的分页查询方法的写法(原因是和ObjectDataSource的运行机制有关):
(1)
MSDN中提到,ObjectDataSource有这样一个事件:ObjectDataSources_Created,它将在每次ObjectDataSource
初始化TypeName指定的类时触发.也就是说,如果分页的方法需要除RowIndex,RecordCount外的其他参数的话可以
借助此事件来增加参数.由此,可以按下面方式增加分页方法:

1 .在DataManager类中,增加一个属性
 
private   bool  _Status;
 
public   bool  Status
 
{
     
get{return  _Status;}
     
set{_Status = values;}
 }


2 .增加一个方法

public  DataSet GetUsers( int  rowIndex, int  recordCount)
{
    
/// <summary>
    
/// 取得用户列表
    
/// </summary>
    
/// <param name="rowIndex">行索引</param>
    
/// <param name="recordCount">页显示量(增量)</param>
    
/// <returns>用户列表数据集</returns>

    public DataSet GetUsers(int rowIndex, int recordCount)
    
{
        OpenConnection();
        
try
        
{
            cmd 
= new SqlCommand();
            cmd.Connection 
= con;
            cmd.CommandType 
= CommandType.StoredProcedure;
            cmd.CommandText 
= "GetUsersByStatus";
            
            SqlParameter spRowIndex 
= new SqlParameter("@RowIndex",SqlDbType.Int,4);
            spRowIndex.Direction 
= ParameterDirection.Input;        
            SqlParameter spRecordCount 
= new SqlParameter("@RecordCount",SqlDbType.Int,4);
            spRecordCount.Direction 
= ParameterDirection.Input;
        SqlParameter spStatus 
= new SqlParameter("@Status", SqlDbType.Bit, 1);
            spStatus.Direction 
= ParameterDirection.Input;

            cmd.Parameters.Add(spRowIndex);
            cmd.Parameters.Add(spRecordCount);
        cmd.Parameters.Add(spStatus); 
//在这里将增加的参数值隐式加入到查询

            spRowIndex.Value 
= rowIndex;
            spRecordCount.Value 
= recordCount;
        spStatus.Value 
= _Status;
        
            da 
= new SqlDataAdapter(cmd);
            DataSet ds 
= new DataSet();
        
            da.Fill(ds, 
"MyUsers");

            
return ds;
    }

        
catch (SqlException ex)
        
{
            
throw new Exception("无法取得有效数据", ex);
        }

        
finally
        
{
            CloseConnection();
        }

    }


    
/// <summary>
    
/// 根据用户状态取得用户总数
    
/// </summary>
    
/// <returns>用户总数</returns>

    public int GetUsersCount()
    
{
        OpenConnection();
        
try
        
{
            cmd 
= new SqlCommand();
            cmd.Connection 
= con;
            cmd.CommandType 
= CommandType.StoredProcedure;
            cmd.CommandText 
= "GetUsersCountByStatus";

            SqlParameter spStatus 
= new SqlParameter("@Status", SqlDbType.Bit, 1);
            spStatus.Direction 
= ParameterDirection.Input;

            cmd.Parameters.Add(spStatus);

            spStatus.Value 
= _Status;

            
int count = Convert.ToInt32(cmd.ExecuteScalar().ToString());
            
return count;
        }

        
catch (SqlException ex)
        
{
            
throw new Exception("无法取得有效数据", ex);
        }

        
finally
        
{
            CloseConnection();
        }

    }

}


3 .在页面增加一个DropDownList,设置如下
< asp:DropDownList ID = " ddShowUsersByStaus "  runat = " server "  AutoPostBack = " True " >                
    
< asp:ListItem Selected = " True "  Value = " all " > 全部 </ asp:ListItem >
                
< asp:ListItem Value = " false " > 禁用 </ asp:ListItem >
                
< asp:ListItem Value = " true " > 激活 </ asp:ListItem >
</ asp:DropDownList ></ div >

4 .在WebSite增加一个事件
 
protected  ObjectDataSource_Created( object  sender, ObjectDataSourceEventArgs e)
 
{
     
if(!ddShowUsersByStaus.SelectedValue.Equals("all"))
     
{
         DataManager  dm  
= (DataManager)e.GetInstance();
         dm.Status 
= ddShowUsersByStaus.SelectedValue;
     }

 }
        这样,在选择了用户状态之后,ObjectDataSource会首先将选择的值赋给Status属性,然后才会去调用GetUsers()方法取得用户列表 至此,我们可以在不必改变原有方法接口的前提下,解决增加了参数的问题.
 然而,这样似乎还是很麻烦,无谓在DataManager类中增加属性,使得Web和DataManager成为紧耦合应用,同时也非"懒人"所为.再介绍 一种更为灵活的方式供大家参考


(2)
ObjectDataSource类的SelectParameters是可以动态改变的,据此,我们按下面的顺序来更改应用.

1 .Datamanager中重载GetUsers()和GetUsersCount()两个方法.代码如下

public  DataSet GetUsers( int  rowIndex,  int  recordCount, bool  status)
    
{
        OpenConnection();
        
try
        
{
            cmd 
= new SqlCommand();
            cmd.Connection 
= con;
            cmd.CommandType 
= CommandType.StoredProcedure;
            cmd.CommandText 
= "GetUsersByStatus";

            SqlParameter spRowIndex 
= new SqlParameter("@RowIndex", SqlDbType.Int, 4);
            spRowIndex.Direction 
= ParameterDirection.Input;
            SqlParameter spRecordCount 
= new SqlParameter("@RecordCount", SqlDbType.Int, 4);
            spRecordCount.Direction 
= ParameterDirection.Input;
            SqlParameter spStatus 
= new SqlParameter("@Status", SqlDbType.Bit, 1);
            spStatus.Direction 
= ParameterDirection.Input;

            cmd.Parameters.Add(spRowIndex);
            cmd.Parameters.Add(spRecordCount);
            cmd.Parameters.Add(spStatus);

            spRowIndex.Value 
= rowIndex;
            spRecordCount.Value 
= recordCount;
            spStatus.Value 
= status;            

            da 
= new SqlDataAdapter(cmd);
            DataSet ds 
= new DataSet();

            da.Fill(ds, 
"MyUsers");

            
return ds;            
        }

        
catch (SqlException ex)
        
{
            
throw new Exception("无法取得有效数据", ex);
        }

        
finally
        
{
            CloseConnection();
        }

    }


    
public   int  GetUsersCount( bool  status)
    
{
        OpenConnection();
        
try
        
{
            cmd 
= new SqlCommand();
            cmd.Connection 
= con;
            cmd.CommandType 
= CommandType.StoredProcedure;
            cmd.CommandText 
= "GetUsersCountByStatus";

            SqlParameter spStatus 
= new SqlParameter("@Status", SqlDbType.Bit, 1);
            spStatus.Direction 
= ParameterDirection.Input;

            cmd.Parameters.Add(spStatus);

            spStatus.Value 
= status;

            
int count = Convert.ToInt32(cmd.ExecuteScalar().ToString());
            
return count;
        }

        
catch (SqlException ex)
        
{
            
throw new Exception("无法取得有效数据", ex);
        }

        
finally
        
{
            CloseConnection();
        }

    }


2 .在页面增加DropDownList设置如下:
< asp:DropDownList ID = " ddShowUsersByStaus "  runat = " server "  AutoPostBack = " True "  
OnSelectedIndexChanged
= " ddShowUsersByStaus_SelectedIndexChanged " >
    
< asp:ListItem Selected = " True "  Value = " all " > 全部 </ asp:ListItem >
    
< asp:ListItem Value = " false " > 禁用 </ asp:ListItem >
    
< asp:ListItem Value = " true " > 激活 </ asp:ListItem >
</ asp:DropDownList >

3 .在DropDownList的SelectedIndexChanged事件增加代码:

protected   void  ddShowUsersByStaus_SelectedIndexChanged( object  sender, EventArgs e)
{
    objMyUsers.SelectParameters.Clear();
    gvMyUsers.PageIndex 
= 0;
    
if ("all".Equals(ddShowUsersByStaus.SelectedValue))
    
{

    }


    
else
    
{
        Parameter pStatus 
= new Parameter("status", TypeCode.Boolean);
        
        objMyUsers.SelectParameters.Add(pStatus);
        pStatus.DefaultValue 
= ddShowUsersByStaus.SelectedValue;
    }
       
}

        如何?这样看上去只是给ObjectDataSource的参数集合动态增加了一个参数,它自己就会去调用重载后的分页方法,省得我们在专门指定 SelectMethod.编码简洁多了,维护起来也更容易,增加分页的条件无非是增加重载的方法和变更动态增加参数的代码,无意间发现这就是"开-闭" 原则的小应用.(估计没人在乎这个吧...)

        采用GridView作为数据绑定控件,好处在于ObjectDataSource会根据GridView的变化自动向数据库取出当前需要的数据,而不用 我们为它担忧一丝一毫.至少不用为取得空数据和页码不正确睡不着觉了.数据操作应该是完整的增删查改.我们把查询做得很彻底了,后面将介绍增加,删除,修 改记录的操作,我想,GridView&ObjectDataSource
不会让大家失望的.未完待续.......(To Be Continue!!)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值