位置:海鸟网 > IT > ASP.NET >

用ASP.NET在同一网页中显示主从关系表的相关数据

    
  摘要:
  DataSet是数据集在内存中的表示方法,数据集可以有主从关系的数据表,在ACCESS中这种关系表现的很直观,本文讨论在同一网页上直观地显示有主从关系的相应数据的程序设计和程序。
  
  --------------------------------------------------------------------------------
  
  目录
  方法
  Tables和ImageButtons的ID的命名规则
  网页上Table的字段长度的估计
  主要程序
  事件过程
  应用实例
  
  --------------------------------------------------------------------------------
  
  方法 :
  对DataSet中的每一张表,如果有子表,将这张表的字段名行和每一纪录行在网页上都显示为只有一行的Table,并在记录行Table的第一列置上一个ImageButton,以便程序控制展开或关闭相应的子表的纪录行所形成的Table或Tables。对于每一纪录行,子表有相应的记录行,若子表还有子表,则对子表重复上述过程,即将子表的字段名行与相应的记录行在网页上都显示为只有一行的Table,并在记录行Table的第二列置上一个ImageButton,反之将子表的字段名行与相应的纪录行在网页上显示为一个Table。利用Table的Visible属性,可以控制子表相应记录行的显示。显然可以使用递归调用实现这一过程。
  
  --------------------------------------------------------------------------------
  
  Tables和ImageButtons的ID的命名规则:
  用对ImageButton的点击,程序控制网页上的相应的Tables的显示与隐藏,这些ImageButton.id和Table.id的命名就需要一定的规则。
  对DataSet中的第一张主表:
  由字段行生成的网页Table的id命名为t0
  由记录行生成的网页Tables的id分别为t1,t2,...tn ,与这些Tables相对应的ImageButton.id命名为 e1,e2,...en, 这里 n:主表的记录行数
  对DataSet中的子表:
  子表中的记录行都是隶属于主表中的某一记录行,因此这些记录行生成的网页Tables也隶属于主表某一记录行所生成网页的Table,如隶属于t2的Tables命名为t2-0,t2-1,t2-3...,其中t2-0为子表的字段名行在网页上生成的Table.id名,其余以此类推,若子表没有子表了,即最后一个子表,则t2-0是包含子表的字段名行和相应的子表记录行在网页上生成的Table.id名。
  与这些table.id相对应的ImageButton.id分别命名为e2-1,e2-2,...。
  
  --------------------------------------------------------------------------------
  
  网页上Table的字段长度的估计:
  DataSet中的每一张表都会在网页上生成一些Table,这些Tables的外在形式应该是相同的。即Tables的相同的Cell应有同样的长度。函数子程序SetCellSize计算DataTable的每一字段平均字符数,和字段名的字符数,并取其大者,若字段的某一纪录或字段名都是ASCII字符,则其字符数减半。用此数据便可估计网页上的Table的相应字段的显示长度。
  下面是SetCellSize的程序,容易理解。
  Function SetCellSize(myTable as DataTable)
  dim myRow as DataRow
  dim i,j,k,m as integer
  dim aa() as integer
  dim myBool as Boolean
  
  m=myTable.columns.count-1
  redim aa(m)
  for i=0 to m
   aa(i)=0
  next
  
  for each myRow in myTable.rows '计算每一字段的平均字符长度
   for i=0 to myTable.columns.count-1
   dim mystr as string
   mystr=myRow(myTable.columns(i)).tostring
   j=len(mystr)
   if j>0 then
   myBool=true
   for k=1 to j '判断dataTable中的每一项是否包括汉字
   dim str1 as char=mid(mystr,k,1)
   if ascw(str1)>255 then '有非ASCII字符
   myBool=false
   exit for
   end if
   next
   if myBool then j=(j/2+0.5) '都是ASCII字符,字符串长度减半
   aa(i)+=j
   end if
   next
  next myRow
  
  k=myTable.rows.count
  for i=0 to m
   aa(i)=aa(i)/k 'DataTable的每一列的平均长度
  next
  
  for i=0 to myTable.columns.count-1 '对每一字段名
   dim str2 as string=myTable.columns(i).columnname
  
   j=len(str2)
   if j>0 then
   myBool=true
   for k=1 to j '判断字段名中是否包括汉字
   dim str1 as char=mid(str2,k,1)
   if ascw(str1)>255 then '有非ASCII字符
   myBool=false
   exit for
   end if
   next
   if myBool then j=(j/2+0.5) 'ASCII字符,字符串长度减半
   if j>aa(i) then aa(i)=j
   end if
  next
  SetCellSize=aa
  end Function
  
  
  
  
  --------------------------------------------------------------------------------
  
  主要程序:
  子程序ShowTables设置一些初始值,然后调用子程序ShowChildRows。
  子程序ShowChildRows的参数说明:
  Rows:是一个DataRow数组,第一次调用ShowChildRows时,是DataTable的所有的记录行。以后递归调用ShowChildRows时,是与父表某一记录行相关的子表的一些记录行。
  myTable:Rows所属的DataTable,程序将使用它的Columns,即字段名行。
  aa:函数子程序SetCellSize返回的一维整型数组。
  spaces:整型参数,用于在网页显示Tables时,这些Tables左侧应设置几个空单元格,以显示Table的隶属关系。
  signal:字符串参数,ImageButton的id值,用于生成相关的Tables和ImageButtons的id。
  因为要在网页中添加Table控件,所以在网页中应有一个id为form1的Form控件。
  动态地创建一个Table有三个步骤,首先,创建 TableCell 对象,即行中的单元格,添加单元格的内容有两种方法:设置 Text 属性,或者向 TableCell 的 Control.Controls 集合添加控件,程序中对某些单元格添加ImageButton控件;接下来,创建 TableRow 以表示表中的行,将此前创建的 TableCell 对象添加到 TableRow 的 Cells 集合中。最后,将 TableRow 添加到 Table 控件的 Rows 集合中。
  以下是程序:
  Sub ShowTables(mySet as DataSet)
  dim spaces as integer=0
  dim aa() as integer
  dim i,d as integer
  dim signal as string=""
  
  dim myTable as dataTable=mySet.tables(0)
  dim rows() as DataRow
  d=myTable.rows.count-1
  redim rows(d)
  
  
  for i=0 to myTable.rows.count-1
   rows(i)=myTable.rows(i)
  next
  
  aa=SetCellSize(myTable)
  Call ShowChildRows(rows,aa,myTable,spaces,signal)
  End Sub
  
  
  
  Sub ShowChildRows(rows() as DataRow,aa() as integer,myTable as DataTable,spaces as integer,signal as string)
  dim i,j,k,m,leng as integer
  dim fontsize as integer=10
  
  dim myRow as DataRow
  dim myCol as DataColumn
  
  dim testTable as Table
  
  dim Cell as TableCell
  dim Row as TableRow
  dim myBool as Boolean
  dim myimage as ImageButton
  
  dim ChildRows() as DataRow
  dim ChildTable as DataTable
  
  dim myRel as DataRelation
  dim bb() as integer
  
  dim CellStyle as new TableItemStyle
  cellStyle.borderwidth=unit.pixel(1)
  cellStyle.borderstyle=Borderstyle.solid
  cellStyle.wrap=false
  
  if myTable.ChildRelations.count=1 then '有从表
   myRel=myTable.ChildRelations(0)
   ChildTable =myRel.ChildTable
   m=ChildTable.Columns.count-1
   redim bb(m)
   myBool=True
   bb=SetCellSize(ChildTable)
  end if
  
  testTable=New Table
  testTable.borderwidth=unit.pixel(1)
  testTable.cellspacing=0
  testtable.cellPadding=0
  testTable.font.name="宋体"
  testTable.font.size=fontunit.point(fontsize)
  testTable.visible=true
  if signal<>"" then '递归调用时,字段名行形成的Table.id的赋值
   leng=len(signal)
   testTable.id="t" & mid(signal,2,leng-1) & "-0"
   testtable.visible=false
  else
   testTable.id="t" & "0" '初始时,字段名行形成的Table.id
   testTable.visible=true
  end if
  
  form1.controls.add(testtable)
  
  '********** 以下程序为生成表的字段名称行的Table ********************
  
  Row=New tableRow
  Row.borderwidth=unit.pixel(1)
  m=rows.length
  
  if spaces>0 then
   for i=1 to spaces
   cell=new Tablecell
   cell.applyStyle(CellStyle)
   cell.width=unit.pixel(13)
   if not myBool then cell.rowspan=m+1
   row.cells.add(cell)
   next
  end if
  
  if myBool then
   cell=new Tablecell
   cell.applystyle(CellStyle)
   cell.backcolor=color.lightgray
   cell.bordercolor=color.black
   cell.width=unit.pixel(13)
   row.cells.add(cell)
  end if
  
  m=myTable.Columns.count-1
  
  for i=0 to m
   Cell=new tableCell
   dim str2 as string
   cell.applystyle(cellstyle)
   cell.backcolor=color.lightgray
   cell.bordercolor=color.black
   cell.text= myTable.columns(i).columnName
   cell.HorizontalAlign=HorizontalAlign.Center
   k=(fontsize+6)*aa(i)
   cell.width=unit.pixel(k)
   row.Cells.add(cell)
  next
  testtable.Rows.add(row)
  
  '************* 以下程序为生成表的各行纪录的Tables *********************
  
  for i=0 to rows.length-1
   if myBool then
   testTable=New table
   testTable.borderwidth=unit.pixel(1)
   testTable.cellspacing=0
   testtable.cellPadding=0
   testTable.font.name="宋体"
   testTable.font.size=fontunit.point(fontsize)
   testTable.visible=true
   if signal<>"" then
   testTable.id="t" & mid(signal,2,leng-1) & "-" & (i+1).tostring
   testtable.visible=false
   else
   testTable.id="t" & (i+1).tostring
   testTable.visible=true
   end if
   form1.controls.add(testtable)
   end if
  
   myRow=rows(i)
  
   Row=New tableRow
   if myBool then
   if spaces>0 then
   for k=1 to spaces
   cell=new Tablecell
   cell.applystyle(cellstyle)
   cell.width=unit.pixel(13)
   row.cells.add(cell)
   next
   end if
  
   Cell=New tableCell
   cell.width=unit.pixel(13)
   cell.applystyle(CellStyle)
  
   myimage=New imagebutton
   myimage.imageurl="close.gif"
   if signal<>"" then
   myimage.id=signal & "-" & (i+1).tostring
   else
   myimage.id="e" & (i+1).tostring
   end if
   AddHandler myimage.Command, AddressOf ImageButton_Command
   myimage.imagealign=ImageAlign.absmiddle
   cell.controls.add(myimage)
   row.cells.add(cell)
   end if
  
   m=myTable.columns.count-1
  
   for j=0 to m
   cell=new tablecell
   cell.ApplyStyle(CellStyle)
   cell.text=myRow(myTable.columns(j)).tostring
   k=(fontsize+6)*aa(j)
   cell.width=unit.pixel(k)
   row.cells.add(cell)
   next
   testtable.rows.add(row)
  
  
   if myBool then '若有从表,递归调用
   dim spaces2 as integer
   spaces2=spaces+1
   ChildRows=myRow.GetChildRows(myRel)
   call ShowChildRows(ChildRows,bb,ChildTable,spaces2,myimage.id)
   end if
  next
  End Sub
  
  
  
  
  --------------------------------------------------------------------------------
  
  事件过程:
  在“Tables和ImageButtons的ID的命名规则”一节中给出了命名的规则,这里举例说明:
  如果点击了id为e1的ImageButton,它所对应的网页上的Table的id为t1,与t1相关的子表上的相应的记录行在网页上形成id为t1-1,t1-2,...t1-n的Tables,这里 n为子表上的相应的记录行数,而t1-0为子表的字段名行在网页上形成的Table。如果e1的ImageUrl为“”close.gif,则将其设置为“”open.gif,并将t1-0,t1-1,...t1-n的Visible属性设置为True。反之,除了要将e1的ImageUrl改为close.gif和将t1-0,t1-1,...t1-n的Visible属性改为False外,如果t1-1,t1-2,...t1-n有对应id为e1-1,e1-2,...e1-n的ImageButton的,而这些ImageButtons中的某些ImageUrl为open.gif,即子表的子表的某些记录行生成的Tables是打开的,则这些ImageUrl设置为close.gif。
  文章标题:Using Web Services Enhancements to Send SOAP Messages with Attachments
  程序如下:
  Sub ImageButton_Command(Sender as object,e as CommandEventArgs)
  dim myControl as Control
  dim str1 as string
  dim leng as integer
  
  str1=sender.id
  leng=len(str1)
  str1="t" & mid(str1,2,leng-1) & "-"
  
  if Sender.ImageUrl="close.gif" then
   Sender.ImageUrl="open.gif"
   for each myControl in form1.controls
   dim pos1 as integer=instr(leng+2,myControl.id,"-")
   if left(myControl.id,leng+1)=str1 and pos1=0 then myControl.visible=true
   next
  else
   Sender.ImageUrl="close.gif"
   for each myControl in form1.controls
   dim str0 as string=myControl.id
   if left(myControl.id,leng+1)=str1 then
   dim dTable as table
   dtable=ctype(myControl,table)
   if dtable.controls.count>0 then
   dim rowControl as control
   for each rowControl in dtable.controls
   dim drow as tablerow
   drow=ctype(rowControl,tablerow)
   if drow.controls.count>0 then
   dim cellControl as control
   for each cellControl in drow.controls
   dim dcell as tablecell
   dcell=ctype(cellControl,TableCell)
   if dcell.controls.count>0 then
   dim imageControl as control
   for each imageControl in dcell.controls
   dim dimage as imageButton
   dimage=ctype(imageControl,imageButton)
   dimage.ImageUrl="close.gif"
   next
   end if
   next
   end if
   next
   end if
   myControl.visible=false
   end if
   next
  end if
  End Sub
  
  
  
  
  --------------------------------------------------------------------------------
  
  应用实例:
  以罗斯文数据库为例,该数据库有客户、订单和订单明细三个表文件,客户和订单两张表在字段名“客户ID”有一对多的关系,订单和订单明细在字段名“订单ID”有一对多的关系。下述程序连接数据库,形成DataSet后,调用子程序ShowTables。
  <%@Import Namespace=System.Data.oledb%>
  <%@Import Namespace=System.Data%>
  <%@Import Namespace=System.drawing%>
  <html>
  <head>
  
  <script language="VB" runat="server">
  sub Page_Load(Sender as Object, e as EventArgs)
  
  dim dsDataSet as DataSet=new DataSet()
  dim Constr,Conn as string
  
  dsdataSet=cache("mySet")
  if dsDataSet is Nothing
   Constr =server.mappath("northwind.mdb")
   Conn="provider=microsoft.jet.oledb.4.0; data source=" & Constr
   dsDataSet=new DataSet()
   dim odA as oledbDataAdapter=new oledbDataAdapter("select * from 客户",Conn)
   odA.fill(dsDataSet,"Customers")
  
   odA.SelectCommand.CommandText="select * from 订单"
   odA.fill(dsDataSet,"Orders")
  
   odA.SelectCommand.CommandText="select * from 订单明细"
   odA.fill(dsDataSet,"Order_details")
  dsDataSet.Relations.Add("M",dsDataSet.Tables(0).Columns("客户ID"),dsDataSet.Tables(1).Columns("客户ID"))
  dsDataSet.Relations.Add("N",dsDataSet.Tables(1).Columns("订单ID"),dsDataSet.Tables(2).Columns("订单ID"))
  Cache("mySet")=dsdataSet
  end if
  call ShowTables(dsDataSet)
  end sub
  
   
  
  '子程序ShowTables添加处
  
  '子程序SetCellSize添加处
  
  '子程序ShowChildRows添加处
  
  '子程序ImageButton_Command添加处
  </script>
  
  </head>
  <body>
  <form runat="server">
  </form>
  </body>
  </html>
  
  将上述程序copy到记事本中,并将前面的程序copy到相应的子程序添加处,注意:在上述过程中可能会出现文本的断行错误,在加以修改后,命名为.aspx文件,运行结果如下图:
  
  

用ASP.NET在同一网页中显示主从关系表的相关数据