MS访问控制属性.类型没有意义

问题描述 投票:3回答:2

我过去曾写过处理TableDef和Field属性的代码。这并不难,它只是涉及到在Field.Properties集合中循环,并沿途进行一定量的错误检查。Property.Name、Property.Type和Property.Value产生了我们需要的一切。

问题是:我刚刚写了一些代码来为Form和Report控件做同样的属性枚举。属性名和值都很好,但.Type不正确。举个例子。

Public Sub TestPropTypes()
Dim dbs As DAO.Database

    Set dbs = CurrentDb()

    Dim td As TableDef
    Dim fld As DAO.Field

    Set td = dbs.TableDefs("CalendarEvent_")
    Set fld = td.Fields("EventDescription")
    PrintObjectProps fld

    Dim f As Form
    Dim c As Control

    DoCmd.OpenForm "fmCalendarDates", acDesign
    Set f = Forms!fmCalendarDates
    Set c = f.Controls("Label7")
    PrintObjectProps c
End Sub

Private Sub PrintObjectProps(c As Object, Optional RecursionDepth As Integer = 0)
Dim ExistingProperty As DAO.Property
Dim PropCount As Integer
Dim GotValue As Boolean
Dim v As Variant

    Debug.Print c.Name

    For Each ExistingProperty In c.Properties
        If PropCount > 12 Then Exit Sub

        GotValue = True
        On Error Resume Next
        v = ExistingProperty.Value
        If Err.number <> 0 Then GotValue = False
        On Error GoTo 0

        If GotValue Then
            Debug.Print "  " & ExistingProperty.Name & " " _
                & GetFieldDDLTypeName(ExistingProperty.Type) & "(" & ExistingProperty.Type & ") " _
                & xf.Gen.dq(CStr(ExistingProperty.Value))
        End If

        PropCount = PropCount + 1
    Next
End Sub

Public Function GetFieldDDLTypeName(FieldType As DAO.DataTypeEnum) As String
Dim rtnStr As String
    ' as per: http://allenbrowne.com/ser-49.html

    Select Case FieldType
        Case dbBoolean: rtnStr = "YESNO"
        Case dbByte: rtnStr = "BYTE"
        Case dbInteger: rtnStr = "SHORT"
        Case dbLong: rtnStr = "LONG"
        Case dbCurrency: rtnStr = "CURRENCY"
        Case dbSingle: rtnStr = "SINGLE"
        Case dbDouble: rtnStr = "DOUBLE"
        Case dbDate: rtnStr = "DATETIME"
        Case dbBinary: rtnStr = "BINARY"
        Case dbText: rtnStr = "TEXT"
        Case dbLongBinary: rtnStr = "LONGBINARY"
        Case dbMemo: rtnStr = "MEMO"
        Case DBGuid: rtnStr = "GUID"
    End Select

    GetFieldDDLTypeName = rtnStr
End Function

Yields:

TestPropTypes
EventDescription
  Attributes LONG(4) "2"
  CollatingOrder SHORT(3) "1033"
  Type SHORT(3) "10"
  Name MEMO(12) "EventDescription"
  OrdinalPosition SHORT(3) "2"
  Size LONG(4) "100"
  SourceField MEMO(12) "EventDescription"
  SourceTable MEMO(12) "CalendarEvent_"
  DataUpdatable YESNO(1) "False"
  DefaultValue MEMO(12) ""
Label7
  EventProcPrefix DATETIME(8) "Label7"
  Name DATETIME(8) "Label7"
  ControlType BYTE(2) "100"
  Caption DATETIME(8) "Description"
  Visible LONGBINARY(11) "True"
  Width BYTE(2) "1875"
  Height BYTE(2) "285"
  Top BYTE(2) "425"
  Left BYTE(2) "1048"
  BackStyle BYTE(2) "0"
  BackColor SHORT(3) "16777215"
  BorderStyle BYTE(2) "0"
  OldBorderStyle BYTE(2) "0"

所以你可以看到第一组,来自TableDef中的一个Field,产生了我们所期望的结果。

第二组,使用完全相同的渲染代码,来自表单中的一个控件。所有的MEMO属性都以DATETIME的形式出现,所有的YESNO都以LONGBINARY的形式出现,等等。至少是一致的,我大概可以推导出类型转换,并写出转换算法。我一开始觉得可能是用了ADO值(因为YESNO是11),但是和其他ADO值没有一致性,而且我们还明确使用了DAO对象,这样就说不通了。

这是不一致的,我想找出并记录一些合理的解决方案.以前有人遇到过这种情况吗?

在Access 2003和2007上测试过,所以我确信这不是我的Access版本中的一个奇怪的错误。这是一个Access 2003格式的数据库,所以没有任何扩展类型在工作中造成影响。

EDIT:问题解决了,感谢HansUp。现在我们要检查一下tablefield与formreport属性是否确实使用了不同的返回值。我提供了这个。

Public Sub TestPropTypes1()
Dim prop As DAO.Property
Dim dbs As DAO.Database
Set dbs = CurrentDb()

    DoCmd.OpenForm "fmCalendarDates", acDesign

    Debug.Print "Property", "Value", "varType(.Value)", ".Type"
    Debug.Print

    Set prop = dbs.TableDefs("CalendarEvent_").Fields("EventDate").Properties("Name")
    Debug.Print prop.Name, prop.Value, varType(prop.Value), prop.Type

    Set prop = dbs.TableDefs("CalendarEvent_").Fields("EventDate").Properties("Required")
    Debug.Print prop.Name, prop.Value, varType(prop.Value), prop.Type

    Set prop = Forms!fmCalendarDates!Label7.Properties("Name")
    Debug.Print prop.Name, prop.Value, varType(prop.Value), prop.Type

    Set prop = Forms!fmCalendarDates!Label7.Properties("Visible")
    Debug.Print prop.Name, prop.Value, varType(prop.Value), prop.Type
End Sub

返回值

TestPropTypes1
Property      Value          vartype(.Value)   .Type
Name          EventDate      8                12 
Required      False          11               1 
Name          Label7         8                8 
Visible       True           11               11 

这将强烈地表明,TableDef字段属性确实使用了DAO.DataTypeEnum类型,而表单属性似乎产生了VBA.VbVarType的返回。例如,字段的Required属性返回的类型对应于VbVarType的NULL,而它是DataTypeEnum的YesNo。

请注意prop.Type和varType(prop.Value)之间的微妙区别。

虽然我们可以使用varType(prop.value),但这通常会被认为是不好的做法,因为类型可能取决于值的内容(例如,一个Null),而.Type是权威的元数据。在系统属性这样的情况下,值可能表现良好,可能没有实际区别。

真正让人惊讶的是,参考资料中根本没有提到这个问题。

ms-access access-vba dao
2个回答
2
投票

使用 VBA.VbVarType 枚举 Type.

您的代码将一个属性的 Type 身为 DAO.DataTypeEnum. 这将导致代码翻译成 Type 不正确。

其实这不是一个问题,它只出现在表单和报表控件上。 你的表的字段属性也有同样的问题。 例如,输出样本错误地识别了字段的 Name 属性为备忘录类型。

Name MEMO(12) "EventDescription"

但是一个字段的 Name 属性是一个变体,其子类型是字符串。

? CurrentDb.TableDefs("tblFoo").Fields("long_text").Properties("Name").Type
 12 
? VBA.VbVarType.vbVariant
 12
' this is the WRONG translation ...
? DAO.DataTypeEnum.dbMemo
 12 

如果你的目标是翻译属性的 Type 到人性化的文本,考虑 TypeName() 函数。

? TypeName(CurrentDb.TableDefs("tblFoo").Fields("long_text").Properties("Name").Value)
String

如果这个建议不能被接受,你可以创建一个自定义函数来翻译。 Type 到您想要的文本。 然而,翻译 Type 到DDL字段数据类型名称的方法是错误的,我认为。


0
投票

感谢所有这些好的信息.我正在研究这个问题。在Access2019上工作了一些小时后,我可以添加一些提示.我将函数GetFieldDDLTypeName()改为GetFieldVBATypeName(),如下所示,这解决了TypeNames不一致的问题,也解决了复合数组类型。

虽然应用在control.properties上,它显示出一些不一致的地方。

   Control.Property       Type   TypeName      Value
 1-OLEBound.VarOleObject     6    Currency       65
 2-ToggleButton.InSelection 11    Boolean      NULL
 3-Image.InSelection        11    Boolean      6375

Public Function GetVBATypeName(FieldType As VBA.VbVarType) As String
Dim rtnStr As String
If FieldType > 8192 Then
    rtnStr = GetVBATypeName2(8192) & "-" & GetVBATypeName2(FieldType - 8192)
Else
    rtnStr = GetVBATypeName2(FieldType)
End If
GetVBATypeName = rtnStr
End Function

Public Function GetVBATypeName2(FieldType As VBA.VbVarType) As String
Dim rtnStr As String
Select Case FieldType
    Case vbEmpty: rtnStr = "EMPTY"
    Case vbNull: rtnStr = "NULL"
    Case vbInteger: rtnStr = "INTEGER"
    Case vbLong: rtnStr = "LONG"
    Case vbSingle: rtnStr = "SINGLE"
    Case vbDouble: rtnStr = "DOUBLE"
    Case vbCurrency: rtnStr = "CURRENCY"
    Case vbDate: rtnStr = "DATE"
    Case vbString: rtnStr = "STRING"
    Case vbObject: rtnStr = "OBJECT"
    Case vbError: rtnStr = "ERROR"
    Case vbBoolean: rtnStr = "BOOLEAN"
    Case vbVariant: rtnStr = "VARIANT"
    Case vbDataObject: rtnStr = "DATAOBJECT"
    Case vbDecimal: rtnStr = "DECIMAL"
    Case vbByte: rtnStr = "BYTE"
    Case 20: rtnStr = "LONGLONG"  'vbLongLong ...
    Case vbUserDefinedType: rtnStr = "USERDEFINED"
    Case vbArray: rtnStr = "ARRAY"
    Case Else: rtnStr = "Error DataType"
End Select
GetVBATypeName2 = rtnStr
End Function

要注意的是,Case 20,对应于vbLongLong,但不被VBA识别'Case vbLongLong: rtnStr = "LONGLONG" '(=20)这里描述了 。 https:/docs.microsoft.comen-usofficevbalanguagereferenceuser-interface-helpvartype-function#return-values。.如果你有任何更正,请在这里发帖,为更好的软件做贡献。

© www.soinside.com 2019 - 2024. All rights reserved.