本人在VS2005中应用DataGridView显示数据时发现以下问题: 
1、绑定的数据表数据量太大,百万以上记录,造成不可能一次读出,如何每次读100条并实现分页; 
2、如果要实现以DataGridView为基础的用户自定义组合条件查询过滤,有什么好方法; 
3、是否有比较强大的DataGridView扩展控件,DevExpress此类收费的除外。 
请各位大虾多多指教,分不够可以加!!! 

解决方案 »

  1.   

     使用自定义控件把DataGridView封装时,就要设置每页显示多少条记录.
      

  2.   

    DataGrid是一个功能非常强大的ASP.net Web服务器端控件,它除了能够方便地按各种方式格式化显示表格中的数据,还可以对表格中的数据进行动态的排序、编辑和分页。使Web开发人员从繁琐的代码中解放。实现DataGrid的分页功能一直是很多初学ASP.NET的人感到棘手的问题,特别是自定义分页功能,实现方法多种多样,非常灵活。本文将向大家介绍一种DataGird控件在Access数据库下的快速分页法,帮助初学者掌握DataGrid的分页技术。 目前的分页方法 DataGrid内建的分页方法是使用诸如“SELECT * FROM <TABLE>”的SQL语句从数据库表中取出所有的记录到DataSet中,DataGrid控件绑定到该DataSet之后,它的自动分页功能会帮你从该DataSet中筛选出当前分页的数据并显示出来,其他没有用的数据将被丢弃。 还有一种方法是使用自定义分页功能,先将DataGrid的AllowCustomPaging属性设置为True,再利用DataAdapter的Fill方法将数据的筛选工作提前到填充DataSet时,而不是让DataGrid帮你筛选: public int Fill ( 
    DataSet dataSet, //要填充的 DataSet。 
    int startRecord, //从其开始的从零开始的记录号。 
    int maxRecords, //要检索的最大记录数。 
    string srcTable //用于表映射的源表的名称。 
    ); 该方法首先将来自查询处的结果填充到DataSet中,再将不需要显示的数据丢弃。当然,自定义分页功能需要完成的事情还不止这些,本文将在后面详细介绍。 以上两种方法的工作原理都是先从数据库中取出所有的记录,然后筛选出有用的数据显示出来。可见,两种方法的效率基本上是一致的,因为它们在数据访问阶段并没有采取有效的措施来减少Access对磁盘的访问次数。对于小数量的记录,这种开销可能是比较小的,如果针对大量数据的分页,开销将会非常巨大,从而导致分页的速度非常的慢。换句话说,就算每个DataGrid分页面要显示的数据只是一个拥有几万条记录的数据库表的其中10条,每次DataGrid进行分页时还是要从该表中取出所有的记录。 很多人已经意识到了这个问题,并提出了解决方法:用自定义分页,每次只从数据库中取出要显示的数据。这样,我们需要在SQL语句上下功夫了。由于Access不支持真正的存储过程,在编写分页算法上就没有SQL Server那么自由了。SQL Server可以在存储过程中利用临时表来实现高效率的分页算法,受到了广泛的采用。而对于Access,我们必须想办法在一条SQL语句内实现最高效的算法。 用一条SQL语句取得某段数据的方法有好几种。算法不同,效率也就不同。我经过粗略的测试,发现效率最差的SQL语句执行时耗费的时间大概是效率最高的SQL语句的3倍!而且这个数值会随着记录总数的增加而增加。下面将介绍其中两条常用的SQL语句。 为了方便接下来的讨论,我们先约定如下: 变量 说明 变量 说明 
    @PageSize 每页显示的记录总数 @MiddleIndex 中间页的索引 
    @PageCount 分页总数 @LastIndex 最后一页的索引 
    @RecordCount 数据表的记录总数 @TableName 数据库表名称 
    @PageIndex 当前页的索引 @PrimaryKey 主键字段名称 
    @FirstIndex 第一页的索引 @QueryFields 要查询的字段集 变量 定义 
    @PageCount (int)Math.Ceiling((double)@RecordCount / @PageSize) 
    @FirstIndex 0 
    @LastIndex @PageCount – 1 
    @MiddleIndex (int)Math.Ceiling((double)@PageCount / 2) – 1 先让我们看看效率最差的SQL语句: SELECT TOP @PageSize * FROM @TableName 
    WHERE @PrimaryKey NOT IN ( 
    SELECT TOP @PageSize*@PageIndex @PrimaryKey FROM @TableName 
    ORDER BY @PrimaryKey ASC 
    ) ORDER BY @PrimaryKey ASC 这条SQL语句慢就慢在NOT IN这里,主SELECT语句遍历的每个@PrimaryKey的值都要跟子SELECT语句的结果集中的每一个@PrimaryKey的值进行比较,这样时间复杂度非常大。这里不得不提醒一下大家,平时编写SQL语句时应该尽量避免使用NOT IN语句,因为它往往会增加整个SQL语句的时间复杂度。 另一种是使用了两个TOP和三个ORDER BY的SQL语句,如下所示: SELECT * FROM ( 
    SELECT TOP @PageSize * FROM ( 
    SELECT TOP @PageSize*(@PageIndex+1) * FROM @TableName 
    ORDER BY @PrimaryKey ASC 
    ) TableA ORDER BY @PrimaryKey DESC 
    ) TableB ORDER BY @PrimaryKey ASC 
    这条SQL语句空间复杂度比较大。如果要显示的分页面刚好是最后一页,那么它的效率比直接SELECT出所有的记录还要低。因此,对于分页算法,我们还应该具体情况具体分析,不能一概而论。下面将简单介绍一下相关概念,如果您对主键和索引非常熟悉,可以直接跳过。DataGrid是一个功能非常强大的ASP.net Web服务器端控件,它除了能够方便地按各种方式格式化显示表格中的数据,还可以对表格中的数据进行动态的排序、编辑和分页。使Web开发人员从繁琐的代码中解放。实现DataGrid的分页功能一直是很多初学ASP.NET的人感到棘手的问题,特别是自定义分页功能,实现方法多种多样,非常灵活。本文将向大家介绍一种DataGird控件在Access数据库下的快速分页法,帮助初学者掌握DataGrid的分页技术。 目前的分页方法 DataGrid内建的分页方法是使用诸如“SELECT * FROM <TABLE>”的SQL语句从数据库表中取出所有的记录到DataSet中,DataGrid控件绑定到该DataSet之后,它的自动分页功能会帮你从该DataSet中筛选出当前分页的数据并显示出来,其他没有用的数据将被丢弃。 还有一种方法是使用自定义分页功能,先将DataGrid的AllowCustomPaging属性设置为True,再利用DataAdapter的Fill方法将数据的筛选工作提前到填充DataSet时,而不是让DataGrid帮你筛选: public int Fill ( 
    DataSet dataSet, //要填充的 DataSet。 
    int startRecord, //从其开始的从零开始的记录号。 
    int maxRecords, //要检索的最大记录数。 
    string srcTable //用于表映射的源表的名称。 
    ); 该方法首先将来自查询处的结果填充到DataSet中,再将不需要显示的数据丢弃。当然,自定义分页功能需要完成的事情还不止这些,本文将在后面详细介绍。 以上两种方法的工作原理都是先从数据库中取出所有的记录,然后筛选出有用的数据显示出来。可见,两种方法的效率基本上是一致的,因为它们在数据访问阶段并没有采取有效的措施来减少Access对磁盘的访问次数。对于小数量的记录,这种开销可能是比较小的,如果针对大量数据的分页,开销将会非常巨大,从而导致分页的速度非常的慢。换句话说,就算每个DataGrid分页面要显示的数据只是一个拥有几万条记录的数据库表的其中10条,每次DataGrid进行分页时还是要从该表中取出所有的记录。 很多人已经意识到了这个问题,并提出了解决方法:用自定义分页,每次只从数据库中取出要显示的数据。这样,我们需要在SQL语句上下功夫了。由于Access不支持真正的存储过程,在编写分页算法上就没有SQL Server那么自由了。SQL Server可以在存储过程中利用临时表来实现高效率的分页算法,受到了广泛的采用。而对于Access,我们必须想办法在一条SQL语句内实现最高效的算法。 用一条SQL语句取得某段数据的方法有好几种。算法不同,效率也就不同。我经过粗略的测试,发现效率最差的SQL语句执行时耗费的时间大概是效率最高的SQL语句的3倍!而且这个数值会随着记录总数的增加而增加。下面将介绍其中两条常用的SQL语句。 为了方便接下来的讨论,我们先约定如下: 变量 说明 变量 说明 
    @PageSize 每页显示的记录总数 @MiddleIndex 中间页的索引 
    @PageCount 分页总数 @LastIndex 最后一页的索引 
    @RecordCount 数据表的记录总数 @TableName 数据库表名称 
    @PageIndex 当前页的索引 @PrimaryKey 主键字段名称 
    @FirstIndex 第一页的索引 @QueryFields 要查询的字段集 变量 定义 
    @PageCount (int)Math.Ceiling((double)@RecordCount / @PageSize) 
    @FirstIndex 0 
    @LastIndex @PageCount – 1 
    @MiddleIndex (int)Math.Ceiling((double)@PageCount / 2) – 1 先让我们看看效率最差的SQL语句: SELECT TOP @PageSize * FROM @TableName 
    WHERE @PrimaryKey NOT IN ( 
    SELECT TOP @PageSize*@PageIndex @PrimaryKey FROM @TableName 
    ORDER BY @PrimaryKey ASC 
    ) ORDER BY @PrimaryKey ASC 这条SQL语句慢就慢在NOT IN这里,主SELECT语句遍历的每个@PrimaryKey的值都要跟子SELECT语句的结果集中的每一个@PrimaryKey的值进行比较,这样时间复杂度非常大。这里不得不提醒一下大家,平时编写SQL语句时应该尽量避免使用NOT IN语句,因为它往往会增加整个SQL语句的时间复杂度。 另一种是使用了两个TOP和三个ORDER BY的SQL语句,如下所示: SELECT * FROM ( 
    SELECT TOP @PageSize * FROM ( 
    SELECT TOP @PageSize*(@PageIndex+1) * FROM @TableName 
    ORDER BY @PrimaryKey ASC 
    ) TableA ORDER BY @PrimaryKey DESC 
    ) TableB ORDER BY @PrimaryKey ASC 
    这条SQL语句空间复杂度比较大。如果要显示的分页面刚好是最后一页,那么它的效率比直接SELECT出所有的记录还要低。因此,对于分页算法,我们还应该具体情况具体分析,不能一概而论。下面将简单介绍一下相关概念,如果您对主键和索引非常熟悉,可以直接跳过。
      

  3.   

     楼上的好牛啊,DataGrid是一个不错的东西呢,可以用啊。今天 我就用了,给代码给你看一下吧。
     private void Form1_Load(object sender, EventArgs e)      //加载事件哦!
            {
                conn = new SqlConnection("server=localhost;uid=sa;pwd=sa;database=pubs");
                Adapter = new SqlDataAdapter("select * from datetest", conn);
                ds = new DataSet();
                /*****************************添加标识列***************************************/
                DataTable dt = new DataTable("test");
                DataColumn dc = dt.Columns.Add("pid",typeof(int));
                dc.AutoIncrement = true;
                dc.AutoIncrementSeed = 1;
                dc.AutoIncrementStep = 1;
                ds.Tables.Add(dt);
                /*****************************添加标识列***************************************/
                Adapter.Fill(ds,"test");
                dataGrid1.SetDataBinding(ds,"test");
                /****************************实现翻页*****************************************/
                int rows = ds.Tables["test"].Rows.Count;
                if (rows % pagerows == 0)
                {
                    totalpages = rows / pagerows;
                }
                else
                {
                    totalpages = rows / pagerows + 1;
                }
                beginid = 1;
                endid = beginid + pagerows;
                //筛选
                DataView dv = ds.Tables["test"].DefaultView;
                dv.RowFilter = "pid>="+beginid +"and pid<="+endid;
                dataGrid1.DataSource = dv;            cupages=1;
                this.label1.Text = "当前页为:" + cupages;
                /****************************实现翻页*****************************************/
            }
    //下翻哦!
      //下一页
            private void button6_Click(object sender, EventArgs e)
            {
                if (cupages < totalpages)
                {
                    beginid = endid;
                    endid = beginid + pagerows;                DataView dv = ds.Tables["test"].DefaultView;
                    dv.RowFilter = "pid>=" + beginid + "and pid<=" + endid;
                    //dataGrid1.DataSource = dv;                cupages++;
                    this.label1.Text = "当前面为:"+cupages;
                }
            }
    //上翻哦!//上一页
            private void button5_Click(object sender, EventArgs e)
            {
                if (cupages>1)
                {
                    endid = beginid;
                    beginid = beginid - pagerows;                DataView dv = ds.Tables["test"].DefaultView;
                    dv.RowFilter = "pid>="+beginid+"and pid<="+endid;
                    //dataGrid1.DataSource = dv;                cupages--;
                    this.label1.Text = "当前面为:"+cupages;
                }
            }自己写一片吧
      

  4.   

    哦,还没有把定义的变量告诉你呢   
     SqlCommandBuilder sdbuilder;       
            SqlConnection conn;
            SqlDataAdapter Adapter;
            DataSet ds;
            int totalpages;//总页数
            int cupages=1;//当前页数
            int pagerows=5;//每页的记录条数
            int beginid;//每页的开始页数
            int endid;//每页的结束页数
    上面的就不要说了吧!!!
      

  5.   

    我说各位大侠,我编的是WinForm程序,现在用DataGridView,能不能直接搞一个存储过程之类的,实际点的,哈哈
      

  6.   

    提个建议,建个中间类吧
    class Records
    {
      static int pageCount = getPageCount();
      public static DataTable getPage(int pageNumber)
      {
        //查询特定记录
      }
      static int getPageCount()
      {
        //按照需要计算一共要多少页。
      }
    }然后在窗体中用代码调用:
     DataGridView1.DataSouse = Records.getPage(pageNo)想法就是这样,具体实现就不做了。
      

  7.   

    写了个方法        public static DataTable Select(string args,int page)
            {
                DataGridView da = new DataGridView();
                SqlConnection sqlcon = new SqlConnection();
                sqlcon.ConnectionString = "server = 3CD5107EBF3F4C9; database = Restaurants;uid = sa;pwd = 123";
                SqlDataAdapter adpt = new SqlDataAdapter(args,sqlcon);
                DataSet ds = new DataSet();
                try
                {
                    adpt.Fill(ds,page,100,"Table");
                    return ds.Tables[0];
                }
                catch (Exception ex)
                {
                    System.Console.WriteLine(ex.Message);
                    return new DataTable();
                }
            }