分享
 
 
 

GridView&ObjectDataSource新特性小记 懒人篇

王朝other·作者佚名  2006-05-12
窄屏简体版  字體: |||超大  

GridView&ObjectDataSource新特性小记 懒人篇(一) 分页上路

Posted on 2006-04-13 19:34 笑看千秋_R

--

"懒"序;

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方法,不能增加别的参数,形成矛盾怎么办??欲知解决之道,且等下回分解.....(快跑 啊.....鸡蛋来啦!!)

GridView&ObjectDataSource 新特性小记 懒人篇(二) 分页加速

Posted on 2006-04-17 18:43 笑看千秋_R

--

书接上回,我们提到,如果我们分页的数据,在查询的存储过程中需要更多参数,在使用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!!)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有