请问ADO分页问题(100分)

  • 主题发起人 主题发起人 piaoping
  • 开始时间 开始时间
P

piaoping

Unregistered / Unconfirmed
GUEST, unregistred user!
各们兄弟姐妹:<br>&nbsp; &nbsp; 我想大家都会遇到这个问题,比如主从结构“订单资料窗体“.<br>主表:<br>&nbsp; &nbsp;订单编号: 001 &nbsp;来单日期:2008-11-14 &nbsp;客户:A01<br>从表:<br>&nbsp; &nbsp;物料编码 &nbsp; &nbsp; &nbsp;名称 &nbsp; &nbsp; &nbsp;规格 &nbsp; &nbsp; &nbsp;数量 &nbsp; &nbsp; &nbsp;备注<br>&nbsp; &nbsp;W001 &nbsp; &nbsp; &nbsp; &nbsp; 小汽车 &nbsp; (100*50) &nbsp; &nbsp;500<br>&nbsp; &nbsp;W002 &nbsp; &nbsp; &nbsp; &nbsp; 望远镜 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 100<br>&nbsp; &nbsp;W003 &nbsp; &nbsp; &nbsp; &nbsp; 小鸭子 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 300<br><br>我现在的问题是我们的订单资料表中主表中10多万条这样的记录<br>&nbsp; &nbsp;现在打开“录入订单资料窗体” 就要很久, 我查看了一下内存,一打开,内存马上多<br>了100MB , 订单资料窗体是用 两个TADODataSet , 一个是读取订单主表的ADOSetOrderMaster &nbsp;CommandText 是 "select * from OrderMaster "; <br>另一个是读取订单从表的ADOSetOrderDetail<br>&nbsp; CommandText 是 "select * from OrderDetail where ID=:MasterID"<br><br>我知道问题的原因就是录入订单资料窗体一打开 &nbsp;ADOSetOrderMaster就读取了OrderMaster<br>内的全部数据,造成内存巨耗。 我在网上查了一下资料,很多说分页读取,但都是说说而已.。<br>不知道列位是怎样写读取订单主表的语句 难道是在后面加where <br>但是你加了where,那么这个条件应该怎样写<br>还有我们一般主窗体上都有 &nbsp;首页 前页 下页 末页 等按钮<br>它们的代码分别是 &nbsp;<br>&nbsp; ADOSetMaster.First;<br>&nbsp; ADOSetMaster.Prior;<br>&nbsp; ADOSetMaster.Next;<br>&nbsp; ADOSetMaster.Last;<br><br>如果采用分页技术,这些又该怎样处理,谢谢
 
用分页就自己 写,不用他的上一条下一条<br>procedure TFrmOrderBy.FormShow(Sender: TObject);<br>begin<br>&nbsp; PageCount := 1;<br>&nbsp; StartRowCount := 1;<br>&nbsp; RowCount := ADODataSet1.RecordCount;<br>&nbsp; MaxPageCount := RowCount div PAGEMAXCOUNT; //这些记录可以分多少页<br>&nbsp; if RowCount mod PAGEMAXCOUNT &gt; 0 then //如果过出几行不够一页,那么算一页<br>&nbsp; &nbsp; MaxPageCount := MaxPageCount + 1;<br>&nbsp; MovePage(PageCount);<br>end;<br><br>procedure TFrmOrderBy.BtnCloseClick(Sender: TObject);<br>begin<br>&nbsp; Close;<br>end;<br><br>procedure TFrmOrderBy.MovePage(PCount: Integer);<br>var<br>&nbsp; one: Boolean;<br>&nbsp; StartId: string;<br>&nbsp; EndId: string;<br>begin<br>&nbsp; one := False;<br>&nbsp; CurrRowCount := PCount * PAGEMAXCOUNT;<br>&nbsp; StartRowCount := CurrRowCount - PAGEMAXCOUNT + 1; //起始位置<br>&nbsp; DBGList.DataSource := nil;<br>&nbsp; ADODataSet1.Filtered := false;<br>&nbsp; ADODataSet1.MoveBy(StartRowCount - 1);<br>&nbsp; while not ADODataSet1.Eof do<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; if not one then<br>&nbsp; &nbsp; &nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; StartId := ADODataSet1.fieldbyname('id').AsString;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; one := True;<br>&nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; if (CurrRowCount = ADODataSet1.RecNo) or (ADODataSet1.RecNo = rowcount) then<br>&nbsp; &nbsp; &nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; EndId := ADODataSet1.fieldbyname('id').AsString;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ADODataSet1.Filtered := false;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ADODataSet1.Filter := 'id&gt;=' + StartId + ' and id&lt;=' + EndId;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ADODataSet1.Filtered := true;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DBGList.DataSource := DataSource1;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; exit;<br>&nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; ADODataSet1.Next;<br>&nbsp; &nbsp; end;<br>end;<br><br>procedure TFrmOrderBy.btn2Click(Sender: TObject);<br>begin<br>&nbsp; if not (PageCount + 1 &gt; MaxPageCount) then<br>&nbsp; &nbsp; PageCount := PageCount + 1;<br>&nbsp; MovePage(PageCount);<br>end;<br><br>procedure TFrmOrderBy.btn1Click(Sender: TObject);<br>begin<br>&nbsp; PageCount := PageCount - 1;<br>&nbsp; if PageCount &lt;= 1 then<br>&nbsp; &nbsp; PageCount := 1;<br>&nbsp; MovePage(PageCount);<br>end;<br><br>procedure TFrmOrderBy.Button1Click(Sender: TObject);<br>var<br>&nbsp; txtpage: integer;<br>begin<br>&nbsp; if StrToInt(Trim(edtPage.Text)) &gt; MaxPageCount then<br>&nbsp; &nbsp; txtpage := MaxPageCount<br>&nbsp; else<br>&nbsp; &nbsp; txtpage := StrToInt(Trim(edtPage.Text));<br>&nbsp; MovePage(txtpage);<br>end;
 
谢谢zybzhen大哥,这些正是我想要的,我想再请问一个问题,你的“查找”按钮的代码怎样写?多谢
 
你用zybzhen的技术后,再看看内存情况看,初看了下,数据还是已经全部被取到了内存中,而且分页的速度其慢(如果你表真有10万条记录的话)。 <br>  上次我看到过用原生ADO真正分页从后台读数据的方法,一下子找不到了,LZ可以网上找找看。
 
为什么要一下全部取出来呢,没有任何意义.
 
to &nbsp;sunnyfairy:<br>&nbsp; 你说“为什么要一下全部取出来呢,没有任何意义.”,<br>想请问你和主从结构是怎样操作,或者你的输入记录界面上的这些东东是怎样做的?<br>谢谢
 
现在就让我们使用一个实际的范例来说明如何通过A D O E x p r e s s组件来存取原<br>生A D O对象。这个范例应用程序也刚好展示了A D O E x p r e s s的不足之处,并且说明<br>可以由原生A D O对象弥补A D O E x p r e s s缺失的功能。<br>在A D O的R e c o r d s e t 对象中有一个非常受欢迎的功能就是页次定位,即<br>R e c o r d s e t对象可以把数据表中所有的数据以页次的方式切割,只要程序员指定特<br>定的页次号码就可以存取到这个页次中包含的数据。例如,假设在E m p l o y e e数据<br>表中包含了1 0 0 0笔数据,当页次的大小是1 0笔数据时,那么整个数据表就切割为<br>1 0 0个不同的页次。因此程序员如果指定页次号码为2,就可以存取到第11 ~ 2 0笔的<br>数据。当然,在R e c o r d s e t对象中程序员可以设定页次的大小以及随意设定目前要<br>存取的页次。<br>要使用R e c o r d s e t对象的页面定位功能,程序员可以通过数个R e c o r d s e t对象的<br>属性来完成。这些属性以及它们的意义整理在下面的表格中。<br><br>属性名称意义<br>A b s o l u t e P a g e 改变当前P a g e的位置,设定这个属性可以存取特定P a g e中的数据。这是一<br>个可擦写的属性<br>P a g e C o u n t 数据表中所有的数据除以P a g e S i z e之后所得到的P a g e页数。这是一个只读<br>属性<br>P a g e S i z e 指明每一个P a g e中包含的数据笔数。这是一个可擦写的属性<br><br>因此要使用A D O页面定位功能,程序员只需要使用下面的步骤即可:<br>□ 取得A D O的R e c o r d s e t对象。<br>□ 设定R e c o r d s e t对象的P a g e S i z e属性值,以决定一个页面包含多少笔数。<br>□ 存取R e c o r d s e t对象的P a g e C o u n t以便了解数据表被切割成多少的页面。<br>□ 设定R e c o r d s e t对象的A b s o l u t e P a g e属性值以决定要存取的页面数据。<br>从上面的说明中我们可以知道,要使用A D O页面定位功能的第一步便是取得<br>原生的R e c o r d s e t对象。在前面介绍A D O E x p r e s s组件和原生A D O对象的表格中我们<br>知道,这可以由TA D O D a t a S e t、TA D O Ta b l e或TA D O Q u e r y组件取得。现在就让我<br>们实现一个能够使用A D O页面定位的范例应用程序来说明如何存取A D O E x p r e s s组<br>件没有提供的原生A D O功能。<br>1) 首先在D e l p h i的集成开发环境中建立一个新的项目。然后在窗体中放入<br>TA D O C o n n e c t i o n组件连接到你使用的数据库。在这个范例中我是连接到一个<br>Access 2000的数据表。<br>2) 再放入一个TA D O D a t a S e t以连接到TA D O C o n n e c t i o n组件连接的数据库中的<br>一个数据表。我设定TA D O D a t a S e t组件的C o m m a n d Te x t属性值为select * from<br>Customers order by CustomerID,以便连接到C u s t o m e r s数据表并且取得所有的数据。<br>3) 接着放入图4 - 1 8所示的各种可视化V C L组件。其中代表Page Size的T S p i n E d i t<br>组件可以让程序员输入每一个页面包含的数据笔数。而Page Count的T E d i t控件则是<br>一个只读的控件,它会根据用户在Page Size的T S p i n E d i t组件中设定的页面大小而显<br>2 1 6 Delphi 5.x ADO/MTS/COM+高级程序设计篇<br>下载<br>示整个数据表的数据及切割成的页面总数。最后,绝对P a g e号码这个T S p i n E d i t控件<br>可以让程序员输入要存取的页面号码,以便存取这个页面包含的数据。<br>4) 接着在窗体的下方设定T D a t a G r i d和T D a t a N a v i g a t o r组件连接到TA D O D a t a S e t<br>组件以显示C u s t o m e r s数据表中的数据。<br>图4-<br>5) 最后在“设定属性”按钮的O n C l i c k事件处理程序中撰写如下的程序代码:<br>p r o c e d u r e TForm1.btnSetPageClick(Sender: TObject);<br>b e g i n<br>adodsCustomers.Recordset.PageSize := sedtPageSize.Value;<br>edtPageCount.Text := IntToStr(adodsCustomers.Recordset.PageCount);<br>adodsCustomers.Recordset.AbsolutePage := sedtPageNo.Value;<br>S h o w D a t a ;<br>e n d ;<br>“设定属性”按钮的O n C l i c k事件处理程序首先从Page Size的T S p i n E d i t组件中<br>取出用户设定的页面大小,然后指定给TA D O D a t a S e t封装的原生R e c o r d s e t对象的<br>P a g e S i z e属性值以便决定页面包含的笔数。通过存取TA D O D a t a S e t组件的R e c o r d s e t<br>属性以直接取得原生A D O的R e c o r d s e t对象。<br>第4章深入了解ADO 2 1 7<br>下载<br>接着,O n C l i c k事件处理程序把R e c o r d s e t对象根据页面大小的数据计算出来的<br>总页面数显示在Page Count的T E d i t控件中,最后再把用户要存取的绝对页面号码<br>指定给R e c o r d s e t对象的A b s o l u t e P a g e属性值以便让R e c o r d s e t对象把目前的数据位<br>置定位在这个页面的起始之处。O n C l i c k最后调用S h o w D a t a以便在窗体上方的<br>S t r i n g G r i d中显示这个页面所包含的数据。<br>下面是S h o w D a t a如何显示当前页面中的数据的方法。首先S h o w D a t a调用<br>C l e a r D a t a以清除以前显示的其他页面的数据。接着进入一个循环,这个循环执行<br>的次数就是页面的大小。在循环取得当前记录的数据之后,就调用R e c o r d s e t对象<br>的M o v e N e x t以移动到下一笔数据。<br>p r o c e d u r e T F o r m 1 . S h o w D a t a ;<br>v a r<br>iRow, iCol, iCount : Integer;<br>rs : ADOInt.Recordset;<br>b e g i n<br>C l e a r D a t a ;<br>iRow := 0;<br>iCol := 0;<br>sgridData.Cells[iCol, iRow] :=顾 '客编号' ;<br>I n c ( i C o l ) ;<br>sgridData.Cells[iCol, iRow] :=公 '司名称' ;<br>I n c ( i R o w ) ;<br>D e c ( i C o l ) ;<br>rs := adodsCustomers.Recordset;<br>f o r iCount := 1 t o sedtPageSize.Value d o // Iterate<br>b e g i n<br>sgridData.Cells[iCol, iRow] :=<br>r s . F i e l d s . G e t I t e m ( ' C u s t o m e r I D ' ) . V a l u e ;<br>I n c ( i C o l ) ;<br>sgridData.Cells[iCol, iRow] :=<br>r s . F i e l d s . G e t I t e m ( ' C o m p a n y N a m e ' ) . V a l u e ;<br>I n c ( i R o w ) ;<br>D e c ( i C o l ) ;<br>r s . M o v e N e x t ;<br>e n d ; // for<br>e n d ;<br>图4 - 1 9、图4 - 2 0和图4 - 2 1是这个范例应用程序执行的结果。可以看到,这个范<br>2 1 8 Delphi 5.x ADO/MTS/COM+高级程序设计篇<br>下载<br>例可以通过原生A D O的对象来控制要存取的数据。你可以自己执行这个范例应用<br>程序,而且比较上方S t r i n g G r i d显示的特定页面的数据是否和窗体下方D a t a G r i d中<br>的数据顺序相吻合。你应该会发现R e c o r d s e t对象的页面定位功能的确是非常精确<br>的。<br>图<br><br>上述内容摘至《Delphi5.X ADO/MTS/COM+高级程序设计篇》第4章第4-3-1节<br>昨天正好翻到,不是专门为你翻的哦。(书在DELPHW盒子上可以下载到)
 
采用zybzhen,的方法就失去了分页的真正意义了。
 
这么久了,还是没有得到满意的答案,结贴了
 
多人接受答案了。
 
后退
顶部