在用vb6.0在设计系统中,经常会用到一个表来描述数据库中其他的表的信息,这个在利用case工具建表的时候更能体现出它的优势。下面我来介绍下它的实现方式,以及我所用到的一些场合。本人还是一个在校学生,有考虑不周的敬请见谅。
在数据库编程中,让我们最头痛的莫过于写sql语句了,特别是在erp系统中,设计的表往往很多,如果这时有好几个人同时在编程,而你又没有写系统设计书,那时数据库怎么设计的就是一个很大的问题了,特别是对于新来的程序员,这个问题往往更明显。采用描述表能在一定程度上缓解这个问题。
首先,在整个系统设计中采用case工具建表,case工具不仅要自动创建表,而且还要往描述表中写入这个表的相关信息。(javaeye这个编辑器不支持图片真是烦人。)常用的描述信息由:数据字段名称(fieldEName)、数据字段的中文名称(fieldCName)、数据字段是否可写(writeYN)、数据字段是否要统计(TotalYN)、数据字段的类型(fieldType)、数据长度(fieldLen)、数据显示宽度(fieldWidth)、显示顺序(displayNo)(0为不显示,大于0不能重复)。数据的显示与录入采用mshflexgrid,当然mshflexgrid默认是不支持录入的,我们得对它改改,请看我的下几篇文章。这些字段我们根据需要设置,目的只有一个,显示数据的代码更简单,保存数据我还没有想到很简单的方法,有一个相对简单点的方法,不过影响数据库的设计。
数据库一旦设计好了之后,我们能做的就多了,传统的读取数据的方法固然已经很简单了,但对于erp来说,我们要用的窗体太多,为每个窗体写代码,维护代码的成本太高,所以我通过利用描述表的信息采用了一点小技巧。首先定义已数据类型fieldDescInfo。
Public Type fieldDescInfo FieldEname As String FieldCname As String WriteYN As Integer TotalYN As Integer FieldWidth As Integer FieldType As String End Type
然后定义一个数组。
Dim mFieldInfo() As fieldDescInfo
今后,关于每个字段的信息我都保存到这个数组里面。
好了,看看我们怎么读取数据的代码,我封装成了函数。
Public Function Get_Desc_Info(mGrid As MSHFlexGrid, mCols() As fieldDescInfo, mDescTable As String) '########################################################################################## '从描述表中读取信息,保存到相关数组中,方便调用 '########################################################################################## Dim Sql As String Dim Colstring As String Sql = "SELECT fieldename,fieldcname,displayno,fieldtype,writeYN,fieldWidth From Sys_TableDescrible WHERE (TableEname = '" & mDescTable & "'and displayno>0) order by displayno" TetRec.Open Sql, G_UserCon, adOpenDynamic, adLockOptimistic, adCmdText ReDim mCols(TetRec.RecordCount) mGrid.cols = TetRec.RecordCount + 1 Do While Not TetRec.EOF With mCols(TetRec.Fields("displayno")) .FieldEname = Trim(TetRec.Fields("fieldename")) .FieldCname = Trim(TetRec.Fields("fieldcname")) .FieldType = Trim(TetRec.Fields("fieldtype")) .WriteYN = Trim(TetRec.Fields("writeYN")) '.FieldWidth = TetRec.Fields("fieldWidth") + 0 Colstring = Colstring & .FieldEname & " " & .FieldCname & "," TetRec.MoveNext End With Loop TetRec.Close Colstring = Mid(Colstring, 1, Len(Colstring) - 1) Get_Desc_Info = Colstring End Function
这个函数返回的Colstring很有用的,它是由 fieldEname,fieldCName,fieldEname,fieldCName ,fieldEname,fieldCName …… 构成的,大家估计猜到我要干嘛了,不错,这个就是要显示数据的select部分,之后很多地方都有可能用到的,可惜vb的类很不好用,至少是我很不习惯用,否则有些东西封装起来就好理解多了。
怎么样显示数据的代码基本上出来了吧。那么保存数据呢,下面介绍的情况,适合于除了mshflexgrid中的数据之外不需要保存其他信息的情况,或者另外保存。这就是为什么我说用这个保存我不喜欢了。
主要代码:
Do While i < MSHFlexGrid.rows If MSHFlexGrid.TextMatrix(i, 3) <> "" Then '某一行不能为空 TetRec.AddNew ' -------------------入库表体部分-------------------- For j = 1 To MSHFlexGrid.cols - 1 If TetRec.Fields(mFieldInfo(j).FieldEname).Type = adNumeric Or TetRec.Fields(mFieldInfo(j).FieldEname).Type = adInteger Or TetRec.Fields(mFieldInfo(j).FieldEname).Type = adDouble Or TetRec.Fields(mFieldInfo(j).FieldEname).Type = adSingle Then TetRec.Fields(mFieldInfo(j).FieldEname).Value = Val(MSHFlexGrid.TextMatrix(i, j)) Else TetRec.Fields(mFieldInfo(j).FieldEname).Value = Trim(MSHFlexGrid.TextMatrix(i, j)) End If Next j TetRec.Update End If i = i + 1 Loop
适合这种情况的很少,所以应用面很窄,我想或许借鉴mfc里面的数据绑定的方式,不过我目前没时间去看它的原理(老师分的任务不少啊)。
然后它的一个重要应用就是从excel导入数据到mshflexgrid里面时候要用到。(导入,导出功能还是很常用的吧)
封装后的代码如下:
'###################################################### '本模块用于:描述表方面的操作,如读取描述表,根据描述表导入excel暑假 '###################################################### Public Sub Import_from_Excel(Grid As MSHFlexGrid, DescInfo() As fieldDescInfo, DBName As String) Dim flag() As Integer '-----------用来保存字段是否存在或者需要 Dim conStr As String Dim Excelcon As New ADODB.Connection ReDim flag(Grid.cols - 1) As Integer On Error GoTo err If DBName <> "" Then conStr = "Provider=MSDASQL.1;Persist Security Info=False;Data Source=Excel Files;Initial Catalog=" & Trim(DBName) Excelcon.Open conStr Sql = "select * from [sheet1$]" TetRec.Open Sql, Excelcon, adOpenKeyset, adLockOptimistic, adCmdText '------------检查字段是否存在 For i = 1 To Grid.cols - 1 flag(i) = -1 For j = 0 To TetRec.Fields.count - 1 If InStr(DescInfo(i).FieldCname, Replace(TetRec.Fields(j).Name, " ", "")) <> 0 Or InStr(Replace(TetRec.Fields(j).Name, " ", ""), DescInfo(i).FieldCname) <> 0 Then flag(i) = j '-------------第i行应填第j个字段 Exit For End If Next j If flag(i) = -1 Then If MsgBox("字段“" & DescInfo(i).FieldCname & "”不存在,不需要该字段吗?", vbYesNo, G_ERPWindowsName) = vbNo Then TetRec.Close Excelcon.Close Set Excelcon = Nothing MsgBox "数据导入失败!", vbInformation, G_ERPWindowsName Exit Sub End If End If Next i If Grid.rows - 1 < TetRec.RecordCount Then Grid.rows = TetRec.RecordCount + 1 End If i = 1 TetRec.MoveFirst Do While i <= TetRec.RecordCount '--------填充第i行 For j = 1 To Grid.cols - 1 If flag(j) <> -1 Then Grid.TextMatrix(i, j) = IIf(IsNull(Trim(TetRec.Fields(flag(j)).Value)), "", Trim(TetRec.Fields(flag(j)).Value)) End If Next j TetRec.MoveNext i = i + 1 Loop Grid.rows = i TetRec.Close Excelcon.Close Set Excelcon = Nothing MsgBox "数据导入完成!", vbInformation, G_ERPWindowsName Else MsgBox "无法导入数据,请选择正确数据文件!", vbCritical, G_ERPWindowsName End If Exit Sub err: MsgBox err.Description, vbCritical, G_ERPWindowsName Excelcon.Close Set Excelcon = Nothing End Sub
当然,如果是小项目,用这个或许没太大作用,可是一旦是大项目,每个窗体里面的代码都接近,这时候通过这种方法进行简单的封装,效果还是很明显的。