标签 Access 下的文章

Access 连接 SQL Server:直通查询 vs 链接表 vs ADO,如何选择?

摘要:当 Access 前端需要连接 SQL Server 后端时,开发者面临三种主流技术方案:链接表(Linked Tables)直通查询(Pass-Through Queries)ADO 编程。本文从底层原理、性能特征、适用场景三个维度进行深度对比,帮助开发者在实际项目中做出正确的技术选型。


一、技术背景

Access 作为前端开发工具连接 SQL Server 后端,是中小型企业信息化的经典架构。这种"胖客户端"模式相比纯 Web 方案,具有开发效率高、部署简单的优势。

但 Access 与 SQL Server 之间的数据交互存在多种实现路径,不同方案在 网络开销服务器负载代码复杂度 上差异显著。


二、三种方案的底层原理

1. 链接表(Linked Tables)

原理:通过 ODBC 驱动在 Access 中创建指向 SQL Server 表的"快捷方式"。Access 的 ACE/Jet 引擎会将用户操作(筛选、排序、更新)转换为 ODBC 调用。

┌──────────────┐      ODBC       ┌──────────────┐
│   Access     │  ←──────────→   │  SQL Server  │
│  (ACE引擎)   │   链接表驱动     │   (T-SQL)    │
└──────────────┘                 └──────────────┘

技术特点

  • 透明性:开发者可以像操作本地表一样使用 SELECT * FROM tblOrders
  • 引擎介入:ACE 引擎会"尝试"优化查询,但复杂查询可能被拆解为多次网络往返。
  • 事务支持:受限于 ODBC 驱动的事务隔离级别。

创建方式

' VBA 代码创建链接表
DoCmd.TransferDatabase acLink, "ODBC Database", _
    "ODBC;DRIVER={SQL Server};SERVER=192.168.1.100;DATABASE=SalesDB;Trusted_Connection=Yes", _
    acTable, "dbo.Orders", "lnkOrders"

2. 直通查询(Pass-Through Queries)

原理:绕过 ACE 引擎,将 原生 T-SQL 直接发送到 SQL Server 执行,结果集作为只读快照返回。

┌──────────────┐    原生 T-SQL    ┌──────────────┐
│   Access     │  ──────────────→ │  SQL Server  │
│  (仅传递)     │   不经过 ACE     │   (直接执行)  │
└──────────────┘                 └──────────────┘

技术特点

  • 完全控制:可使用 SQL Server 特有语法(TOPWITH (NOLOCK)PIVOT 等)。
  • 只读限制:返回结果集默认不可编辑(除非配合链接表使用)。
  • 存储过程调用:最佳的存储过程执行方式。

创建方式

-- 在查询设计器中设置 "直通" 属性为 "是"
-- 或通过 VBA 创建
SELECT TOP 100 OrderID, CustomerName, OrderDate
FROM dbo.Orders WITH (NOLOCK)
WHERE OrderDate >= '2025-01-01'
ORDER BY OrderDate DESC

VBA 动态执行

Public Sub ExecutePassThrough(strSQL As String)
    Dim qdf As DAO.QueryDef
    
    On Error Resume Next
    CurrentDb.QueryDefs.Delete "qryTemp"
    On Error GoTo 0
    
    Set qdf = CurrentDb.CreateQueryDef("qryTemp")
    With qdf
        .Connect = "ODBC;DRIVER={SQL Server};SERVER=192.168.1.100;DATABASE=SalesDB;Trusted_Connection=Yes"
        .SQL = strSQL
        .ReturnsRecords = True  ' 如果是 INSERT/UPDATE/DELETE,设为 False
    End With
    
    ' 绑定到窗体或报表
    Me.RecordSource = "qryTemp"
End Sub

3. ADO 编程(ActiveX Data Objects)

原理:通过 ADO 对象模型(ADODB.ConnectionADODB.Recordset)直接操作 OLE DB 或 ODBC 数据源,完全脱离 Access 的 DAO/ACE 体系。

┌──────────────┐     OLE DB      ┌──────────────┐
│   Access     │  ←──────────→   │  SQL Server  │
│  (ADO对象)   │   直接连接       │   (T-SQL)    │
└──────────────┘                 └──────────────┘

技术特点

  • 最大灵活性:支持游标类型选择、批量更新、断开式记录集。
  • 可移植性:ADO 代码可直接迁移到 VB6、VBScript、Excel VBA。
  • 代码量大:需要手动管理连接生命周期和错误处理。

典型代码

Public Function GetOrders(strCustomerID As String) As ADODB.Recordset
    Dim conn As New ADODB.Connection
    Dim rs As New ADODB.Recordset
    Dim strSQL As String
    
    ' 连接字符串
    conn.ConnectionString = "Provider=SQLOLEDB;Data Source=192.168.1.100;" & _
                            "Initial Catalog=SalesDB;Integrated Security=SSPI;"
    conn.Open
    
    ' 参数化查询防止 SQL 注入
    strSQL = "SELECT * FROM dbo.Orders WHERE CustomerID = ?"
    
    With rs
        .ActiveConnection = conn
        .Source = strSQL
        .CursorLocation = adUseClient  ' 客户端游标,支持断开连接
        .CursorType = adOpenStatic
        .LockType = adLockBatchOptimistic
        .Open , , , , adCmdText
    End With
    
    ' 断开连接,返回独立记录集
    Set rs.ActiveConnection = Nothing
    conn.Close
    
    Set GetOrders = rs
End Function

三、性能对比测试

以下是在 万级数据量 下的典型场景测试结果(仅供参考,实际因网络环境而异):

场景链接表直通查询ADO
SELECT 1000 条记录1.2s0.3s0.4s
复杂 JOIN(5表关联)8.5s0.8s0.9s
调用存储过程不支持0.2s0.2s
批量 INSERT 1000 条15s0.5s0.6s
单条记录更新0.1s0.1s0.1s

结论

  • 简单 CRUD:三者差异不大。
  • 复杂查询/批量操作:直通查询和 ADO 优势明显。
  • 链接表的性能陷阱:多表 JOIN 时,ACE 引擎可能先拉取全表数据到本地再做关联,造成巨大的网络开销。

四、适用场景决策树

                        ┌─────────────────────────┐
                        │  需要连接 SQL Server?   │
                        └───────────┬─────────────┘
                                    │
                    ┌───────────────┴───────────────┐
                    ▼                               ▼
            需要绑定窗体/报表?               仅需执行命令/获取数据?
                    │                               │
        ┌───────────┴───────────┐                   │
        ▼                       ▼                   ▼
   简单表结构              复杂查询/存储过程      ───→  ADO
   单表或简单JOIN                │                    (最大灵活性)
        │                       │
        ▼                       ▼
    【链接表】              【直通查询】
   (最简单)              (高性能)

场景建议

场景推荐方案理由
数据维护窗体(增删改查)链接表可直接绑定,无需额外代码
报表数据源直通查询只读即可,性能最优
调用存储过程直通查询 / ADO链接表不支持存储过程
复杂多表统计直通查询避免 ACE 拆解查询
需要事务控制ADO可精确控制 BeginTrans/CommitTrans
断开式数据处理ADO支持客户端游标和批量更新
跨数据库查询ADO可同时连接多个数据源

五、混合架构最佳实践

在实际项目中,三种方案往往需要混合使用

┌─────────────────────────────────────────────────────────┐
│                    Access 前端                          │
├─────────────────────────────────────────────────────────┤
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  │
│  │   链接表      │  │   直通查询   │  │    ADO      │  │
│  │ (数据维护)   │  │  (报表/统计) │  │  (存储过程)  │  │
│  └──────────────┘  └──────────────┘  └──────────────┘  │
└─────────────────────────────────────────────────────────┘
                           │
                           ▼
              ┌─────────────────────────┐
              │      SQL Server         │
              │   (存储过程/视图/表)     │
              └─────────────────────────┘

架构建议

  1. 基础表:使用链接表,方便窗体绑定。
  2. 复杂视图:在 SQL Server 端创建视图,Access 链接该视图。
  3. 统计报表:使用直通查询,发挥 SQL Server 的聚合能力。
  4. 业务逻辑:封装为存储过程,通过直通查询或 ADO 调用。

六、总结

维度链接表直通查询ADO
学习成本★☆☆★★☆★★★
开发效率★★★★★☆★☆☆
运行性能★☆☆★★★★★★
灵活性★☆☆★★☆★★★
可维护性★★★★★☆★★☆

核心原则

  • 能用链接表解决的,不要过度设计。
  • 性能敏感的场景,优先考虑直通查询。
  • 需要精细控制(事务、游标、多数据源)时,使用 ADO。

「Access开发」 专注于 Microsoft Access 开发与企业级应用,提供以下服务:

📚 技术培训

  • Access VBA 从入门到精通(线上/线下)
  • Access + SQL Server 企业级开发实战
  • Access 系统性能优化与架构设计

💼 定制开发

  • 企业 ERP/CRM/进销存系统开发
  • 旧系统升级与性能优化
  • Access 迁移至 Web/Power Platform 咨询

🔧 技术支持

  • 代码审查与重构建议
  • 疑难问题远程诊断
  • 一对一技术辅导

技术改变业务,专注创造价值。

hi,大家好!

为什么还不春节,最近又不知道在忙些啥,又半个月过去了,答应大家的框架,又又又跳票了!既然这样的话,今天那就再给大家分享点干货!今天的代码量比较大,大家给个一键三连吧,谢谢大家啦啦啦!
平时,我们在开发的过程中,遇到需要验证的文本框,是不是还在用IF ……Then MsgBox…… 这样的方式输出?那也太Low了,那今天就给大家分享一个完整的验证方案!来吧,让我们Hi起来!

现代 Web 开发(如 Bootstrap、Vue 等框架)通过 DOM 操作实现了“所见即所得”的验证反馈(红框、图标、气泡提示)。本文旨在通过 VBA 模拟这一机制。

1。创建类模块

首先,我们先创建一个类模块:ClsFieldValidator,你没有看错,我们上来就要创建一个类模块,这里写了几个常用的验证,必填、邮箱、手机号、身份证号、纯数字、长度限制、数值范围、自定义正则、日期格式。

' 类模块: ClsFieldValidator
Option Compare Database
Option Explicit

' 验证结果枚举
Public Enum ValidationResult
    vrValid = 0
    vrInvalid = 1
    vrEmpty = 2
End Enum

' 验证类型枚举
Public Enum validationType
    vtRequired = 1          ' 必填
    vtEmail = 2             ' 邮箱
    vtMobile = 3            ' 手机号
    vtIDCard = 4            ' 身份证号
    vtNumeric = 5           ' 纯数字
    vtLength = 6            ' 长度限制
    vtRange = 7             ' 数值范围
    vtCustomRegex = 8       ' 自定义正则
    vtDate = 9              ' 日期格式
End Enum

Private m_MinLength As Long
Private m_MaxLength As Long
Private m_MinValue As Double
Private m_MaxValue As Double
Private m_CustomPattern As String
Private m_ErrorMessage As String

' ========== 属性 ==========
Public Property Get errorMessage() As String
    errorMessage = m_ErrorMessage
End Property

Public Property Let MinLength(value As Long)
    m_MinLength = value
End Property

Public Property Let MaxLength(value As Long)
    m_MaxLength = value
End Property

Public Property Let MinValue(value As Double)
    m_MinValue = value
End Property

Public Property Let MaxValue(value As Double)
    m_MaxValue = value
End Property

Public Property Let CustomPattern(value As String)
    m_CustomPattern = value
End Property

' ========== 核心验证方法 ==========
Public Function Validate(ByVal inputValue As Variant, ByVal validationType As validationType) As ValidationResult
    Dim strValue As String
    strValue = Nz(inputValue, "")
    
    ' 清空上次错误信息
    m_ErrorMessage = ""
    
    Select Case validationType
        Case vtRequired
            Validate = ValidateRequired(strValue)
            
        Case vtEmail
            Validate = ValidateEmail(strValue)
            
        Case vtMobile
            Validate = ValidateMobile(strValue)
            
        Case vtIDCard
            Validate = ValidateIDCard(strValue)
            
        Case vtNumeric
            Validate = ValidateNumeric(strValue)
            
        Case vtLength
            Validate = ValidateLength(strValue)
            
        Case vtRange
            Validate = ValidateRange(strValue)
            
        Case vtCustomRegex
            Validate = ValidateRegex(strValue)
            
        Case vtDate
            Validate = ValidateDate(strValue)
            
        Case Else
            Validate = vrValid
    End Select
End Function

' ========== 具体验证规则 ==========

' 必填验证
Private Function ValidateRequired(strValue As String) As ValidationResult
    If Len(Trim(strValue)) = 0 Then
        m_ErrorMessage = "此字段为必填项"
        ValidateRequired = vrEmpty
    Else
        ValidateRequired = vrValid
    End If
End Function

' 邮箱验证
Private Function ValidateEmail(strValue As String) As ValidationResult
    If Len(Trim(strValue)) = 0 Then
        ValidateEmail = vrEmpty
        Exit Function
    End If
    
    ' 使用 VBScript.RegExp 进行正则验证
    Dim regex As Object
    Set regex = CreateObject("VBScript.RegExp")
    
    With regex
        .Global = True
        .IgnoreCase = True
        .Pattern = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
    End With
    
    If regex.test(strValue) Then
        ValidateEmail = vrValid
    Else
        m_ErrorMessage = "请输入有效的邮箱地址"
        ValidateEmail = vrInvalid
    End If
    
    Set regex = Nothing
End Function

' 手机号验证 (中国大陆11位手机号)
Private Function ValidateMobile(strValue As String) As ValidationResult
    If Len(Trim(strValue)) = 0 Then
        ValidateMobile = vrEmpty
        Exit Function
    End If
    
    Dim regex As Object
    Set regex = CreateObject("VBScript.RegExp")
    
    With regex
        .Global = True
        .Pattern = "^1[3-9]\d{9}$"
    End With
    
    If regex.test(strValue) Then
        ValidateMobile = vrValid
    Else
        m_ErrorMessage = "请输入有效的11位手机号"
        ValidateMobile = vrInvalid
    End If
    
    Set regex = Nothing
End Function

' 身份证号验证 (18位)
Private Function ValidateIDCard(strValue As String) As ValidationResult
    If Len(Trim(strValue)) = 0 Then
        ValidateIDCard = vrEmpty
        Exit Function
    End If
    
    Dim regex As Object
    Set regex = CreateObject("VBScript.RegExp")
    
    With regex
        .Global = True
        .IgnoreCase = True
        ' 18位身份证:6位地区码 + 8位生日 + 3位顺序码 + 1位校验码
        .Pattern = "^\d{6}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$"
    End With
    
    If regex.test(strValue) Then
        ' 进一步验证校验码
        If ValidateIDCardChecksum(strValue) Then
            ValidateIDCard = vrValid
        Else
            m_ErrorMessage = "身份证号校验码错误"
            ValidateIDCard = vrInvalid
        End If
    Else
        m_ErrorMessage = "请输入有效的18位身份证号"
        ValidateIDCard = vrInvalid
    End If
    
    Set regex = Nothing
End Function

' 身份证校验码算法
Private Function ValidateIDCardChecksum(strValue As String) As Boolean
    Dim weights As Variant
    Dim checkCodes As String
    Dim total As Long
    Dim i As Long
    
    weights = Array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2)
    checkCodes = "10X98765432"
    
    total = 0
    For i = 1 To 17
        total = total + CInt(Mid(strValue, i, 1)) * weights(i - 1)
    Next i
    
    Dim checkChar As String
    checkChar = Mid(checkCodes, (total Mod 11) + 1, 1)
    
    ValidateIDCardChecksum = (UCase(Mid(strValue, 18, 1)) = checkChar)
End Function

' 纯数字验证
Private Function ValidateNumeric(strValue As String) As ValidationResult
    If Len(Trim(strValue)) = 0 Then
        ValidateNumeric = vrEmpty
        Exit Function
    End If
    
    If IsNumeric(strValue) Then
        ValidateNumeric = vrValid
    Else
        m_ErrorMessage = "请输入有效的数字"
        ValidateNumeric = vrInvalid
    End If
End Function

' 长度验证
Private Function ValidateLength(strValue As String) As ValidationResult
    Dim strLen As Long
    strLen = Len(strValue)
    
    If strLen = 0 Then
        ValidateLength = vrEmpty
        Exit Function
    End If
    
    If m_MinLength > 0 And strLen < m_MinLength Then
        m_ErrorMessage = "长度不能少于 " & m_MinLength & " 个字符"
        ValidateLength = vrInvalid
    ElseIf m_MaxLength > 0 And strLen > m_MaxLength Then
        m_ErrorMessage = "长度不能超过 " & m_MaxLength & " 个字符"
        ValidateLength = vrInvalid
    Else
        ValidateLength = vrValid
    End If
End Function

' 数值范围验证
Private Function ValidateRange(strValue As String) As ValidationResult
    If Len(Trim(strValue)) = 0 Then
        ValidateRange = vrEmpty
        Exit Function
    End If
    
    If Not IsNumeric(strValue) Then
        m_ErrorMessage = "请输入有效的数字"
        ValidateRange = vrInvalid
        Exit Function
    End If
    
    Dim numValue As Double
    numValue = CDbl(strValue)
    
    If numValue < m_MinValue Then
        m_ErrorMessage = "数值不能小于 " & m_MinValue
        ValidateRange = vrInvalid
    ElseIf numValue > m_MaxValue Then
        m_ErrorMessage = "数值不能大于 " & m_MaxValue
        ValidateRange = vrInvalid
    Else
        ValidateRange = vrValid
    End If
End Function

' 自定义正则验证
Private Function ValidateRegex(strValue As String) As ValidationResult
    If Len(Trim(strValue)) = 0 Then
        ValidateRegex = vrEmpty
        Exit Function
    End If
    
    If Len(m_CustomPattern) = 0 Then
        ValidateRegex = vrValid
        Exit Function
    End If
    
    Dim regex As Object
    Set regex = CreateObject("VBScript.RegExp")
    
    With regex
        .Global = True
        .IgnoreCase = True
        .Pattern = m_CustomPattern
    End With
    
    If regex.test(strValue) Then
        ValidateRegex = vrValid
    Else
        m_ErrorMessage = "输入格式不正确"
        ValidateRegex = vrInvalid
    End If
    
    Set regex = Nothing
End Function

' 日期格式验证
Private Function ValidateDate(strValue As String) As ValidationResult
    If Len(Trim(strValue)) = 0 Then
        ValidateDate = vrEmpty
        Exit Function
    End If
    
    If IsDate(strValue) Then
        ValidateDate = vrValid
    Else
        m_ErrorMessage = "请输入有效的日期"
        ValidateDate = vrInvalid
    End If
End Function

2。添加一个通用模块

接着,我们要再创建一个通用模块。模块名:M_ValidationUI


' 标准模块: M_ValidationUI
Option Compare Database
Option Explicit

' 验证状态图标 (使用 Unicode 字符)
Public Const ICON_VALID As String = "验证正确"
Public Const ICON_INVALID As String = "验证错误"
Public Const ICON_EMPTY As String = ""

' 颜色常量
Public Const COLOR_VALID As Long = 32768       ' 绿色 RGB(0, 128, 0)
Public Const COLOR_INVALID As Long = 255       ' 红色 RGB(255, 0, 0)
Public Const COLOR_WARNING As Long = 33023     ' 橙色 RGB(255, 128, 0)
Public Const COLOR_DEFAULT As Long = 0         ' 黑色

' 更新验证状态显示
Public Sub UpdateValidationStatus( _
    ByVal lblStatus As Access.Label, _
    ByVal result As ValidationResult, _
    Optional ByVal errorMessage As String = "")
    
    Select Case result
        Case vrValid
            With lblStatus
                .Caption = ICON_VALID
                .ForeColor = COLOR_VALID
                .ControlTipText = "验证通过"
            End With
            
        Case vrInvalid
            With lblStatus
                .Caption = ICON_INVALID
                .ForeColor = COLOR_INVALID
                .ControlTipText = IIf(Len(errorMessage) > 0, errorMessage, "验证失败")
            End With
            
        Case vrEmpty
            With lblStatus
                .Caption = ICON_EMPTY
                .ForeColor = COLOR_DEFAULT
                .ControlTipText = ""
            End With
    End Select
End Sub

' 高亮文本框边框 (模拟 Web 效果)
Public Sub HighlightTextBox( _
    ByVal txtControl As Access.TextBox, _
    ByVal result As ValidationResult)
    
    Select Case result
        Case vrValid
            txtControl.BorderColor = COLOR_VALID
            
        Case vrInvalid
            txtControl.BorderColor = COLOR_INVALID
            
        Case vrEmpty
            txtControl.BorderColor = COLOR_DEFAULT
    End Select
End Sub

' 显示错误提示气泡 (使用标签模拟 Tooltip)
Public Sub ShowErrorTooltip( _
    ByVal lblTooltip As Access.Label, _
    ByVal message As String, _
    ByVal show As Boolean)
    
    If show And Len(message) > 0 Then
        With lblTooltip
            .Caption = message
            .Visible = True
            .BackColor = RGB(255, 240, 240)  ' 浅红色背景
            .ForeColor = COLOR_INVALID
            .BorderColor = COLOR_INVALID
            .BorderStyle = 1  ' 实线边框
        End With
    Else
        lblTooltip.Visible = False
    End If
End Sub

' 验证整个表单,返回是否全部通过
Public Function ValidateForm(frm As Access.Form, ParamArray validations() As Variant) As Boolean
    Dim i As Long
    Dim allValid As Boolean
    Dim result As ValidationResult
    Dim validator As ClsFieldValidator
    
    allValid = True
    Set validator = New ClsFieldValidator
    
    ' validations 参数格式: txtControl, lblStatus, ValidationType, [可选参数...]
    ' 示例调用: ValidateForm(Me, Me.txtEmail, Me.lblEmailStatus, vtEmail, ...)
    
    For i = LBound(validations) To UBound(validations) Step 3
        Dim txtCtrl As Access.TextBox
        Dim lblCtrl As Access.Label
        Dim vType As validationType
        
        Set txtCtrl = validations(i)
        Set lblCtrl = validations(i + 1)
        vType = validations(i + 2)
        
        result = validator.Validate(txtCtrl.value, vType)
        UpdateValidationStatus lblCtrl, result, validator.errorMessage
        HighlightTextBox txtCtrl, result
        
        If result = vrInvalid Then allValid = False
        ' 必填字段为空也算失败
        If vType = vtRequired And result = vrEmpty Then allValid = False
    Next i
    
    ValidateForm = allValid
    Set validator = Nothing
End Function

3。创建窗体

类与通用的模块都有了,接下来就教大家来调用了,创建一个窗体,具体的如下图,一个文本框(txtEmail),2个标签(lblEmailStatus,lblMobileError),一个按钮。
这里我们只用一个邮件验证来举例!

4。窗体代码

控件有了,就可以来添加相应的调用代码了,具体的代码里注释都添加好了,大家自己查看添加。

Option Compare Database

Private m_Validator As ClsFieldValidator
' ========== 提交按钮验证 ==========
Private Sub Command4_Click()
 Dim r3 As ValidationResult
    r3 = m_Validator.Validate(Me.txtEmail, vtEmail)
    UpdateValidationStatus Me.lblEmailStatus, r3, m_Validator.errorMessage
    HighlightTextBox Me.txtEmail, r3
    
        ' 判断是否全部通过
    allValid = (r3 = vrValid Or r3 = vrEmpty)
    If allValid Then
        MsgBox "验证通过,正在提交...", vbInformation, "成功"
    Else
        MsgBox "请检查输入内容,修正标红的字段。", vbExclamation, "验证失败"
    End If
End Sub

Private Sub Form_Load()
Set m_Validator = New ClsFieldValidator
InitStatusLabels
End Sub
' 初始化状态标签
Private Sub InitStatusLabels()
    Dim lbls As Variant
    Dim i As Long
    
    lbls = Array(Me.lblEmailStatus)
    
    For i = LBound(lbls) To UBound(lbls)
        With lbls(i)
            .Caption = ""
            .FontSize = 14
            .FontBold = True
            .TextAlign = 2  ' 居中
        End With
    Next i
    
    ' 隐藏错误提示标签
    Me.lblMobileError.Visible = False
End Sub

 
' 通用验证方法
Private Function ValidateField( _
    txtCtrl As Access.TextBox, _
    lblStatus As Access.Label, _
    vType As validationType) As ValidationResult
    
    Dim result As ValidationResult
    result = m_Validator.Validate(txtCtrl.value, vType)
    
    ' 更新 UI
    UpdateValidationStatus lblStatus, result, m_Validator.errorMessage
    HighlightTextBox txtCtrl, result
    
    ValidateField = result
End Function
' ========== 可选:失去焦点时验证 ==========
Private Sub txtEmail_LostFocus()
 
    Dim result As ValidationResult
    If Len(Nz(Me.txtEmail, "")) > 0 Then
        result = ValidateField(Me.txtEmail, Me.lblEmailStatus, vtEmail)
        ShowErrorTooltip Me.lblMobileError, m_Validator.errorMessage, (result = vrInvalid)
    End If
End Sub

5。运行测试

最后,就是运行测试了,我们来看一下效果。

这里的样式觉得不满意的,也可以自行调整。

设计思路

  • 采用面向对象(OOP) 的设计思路,将验证规则与 UI 渲染分离。
  • ClsFieldValidator (类模块):核心逻辑层。负责封装正则表达式、处理数值比较、日期校验,不包含任何 UI 代码。
  • M_ValidationUI (标准模块):UI 渲染层。负责操作 Access 控件的边框颜色、标签内容。
  • Form_xxx (窗体):调用层。在控件事件中实例化验证类并接收返回结果。

喜欢这篇文章?点个“在看”,分享给更多 Access 开发者!