ข้อเสนอแนะรหัส VBA-Sync

Aug 18 2020

ฉันหวังว่าจะได้รับข้อมูลบางอย่างในโมดูลคลาสที่ฉันออกแบบให้เป็นนามธรรมต้นแบบของการใช้แบบสอบถามแบบอะซิงโครนัสใน VBA cQueryable รองรับทั้งแบบสอบถามแบบซิงโครนัสและอะซิงโครนัส คุณสามารถทำบางอย่างเช่นเรียกแพ็คเกจเพื่อเติมข้อมูลตารางชั่วคราว สิ่งนี้จะทำพร้อมกันเนื่องจากคุณต้องการให้เสร็จสิ้นก่อนที่คุณจะดำเนินการค้นหาที่คุณเลือก หลังจากนั้นคุณจะดำเนินการแบบสอบถามที่เลือกในแต่ละตารางชั่วคราวแบบอะซิงโครนัส

รหัสนี้เป็นเพียงแค่สรุปฟังก์ชันการทำงานจำนวนมากในไลบรารี ADODB ฉันพยายามตั้งชื่อคุณสมบัติและวิธีการให้คล้ายกับสิ่งที่อ็อบเจ็กต์ในไลบรารีนั้นใช้หากเป็นไปได้ คุณสมบัติ connectionString ของฉันมีชื่อคล้ายกับคุณสมบัติเดียวกันในวัตถุ ADODB.Connection และเมธอด CreateParam ของฉันมีชื่อคล้ายกับเมธอด createParameter ของอ็อบเจ็กต์ ADODB.Command

ขั้นตอนใหม่บางส่วนที่ฉันได้แนะนำคือคุณสมบัติ sql สิ่งนี้เก็บเคียวรี sql ที่จะดำเนินการ (แมปนี้กับข้อความคำสั่งในอ็อบเจ็กต์คำสั่ง) อีกประการหนึ่งคือ ProcedureAfterQuery นี่คือการถือโพรซีเดอร์ชื่อที่จะเรียกโดยอ็อบเจ็กต์การเชื่อมต่อหลังจากสร้างเหตุการณ์เมื่อเคียวรีเสร็จสมบูรณ์ อื่น ๆ ได้แก่ SyncExecute และ AsyncExecute ซึ่งควรอธิบายถึงสิ่งที่พวกเขาทำในชื่อของพวกเขา

สิ่งหนึ่งที่ควรทราบเกี่ยวกับสองสิ่งนี้คือ SyncExecute เป็นฟังก์ชันในขณะที่ AsyncExecute เป็นรูทีนย่อย ฉันต้องการให้ SyncExecute ส่งคืนชุดระเบียนเมื่อเสร็จสิ้น แต่สำหรับ AsyncExecute ฉันต้องการให้เป็นส่วนย่อยที่ฉันไม่ต้องการบอกเป็นนัยว่ามันส่งคืนอะไร ฉันใช้รหัสที่คล้ายกัน (แต่ต่างกัน) เพื่อทำสิ่งนี้ ดังนั้นฉันคิดว่าฉันละเมิดหลักการ DRY ฉันสามารถรวมสองสิ่งนี้เพื่อเรียกหนึ่งกระบวนงานย่อยที่ใช้ร่วมกัน ขั้นตอนที่ใช้ร่วมกันนั้นจะซับซ้อนมากขึ้น แต่อย่างน้อยรหัสก็จะถูกแชร์ ฉันไม่มีความชอบไม่ทางใดก็ทางหนึ่ง

แม้ว่า CreateParam จะคล้ายกับเมธอด CreateParameter ของวัตถุคำสั่ง แต่ก็มีความแตกต่างสองประการ หนึ่งคือลำดับของข้อโต้แย้งแตกต่างกัน ส่วนใหญ่เป็นเพราะพารามิเตอร์ขนาดและทิศทางแสดงรายการเป็นพารามิเตอร์ทางเลือกพร้อมค่าเริ่มต้น ค่าเริ่มต้นสามารถใช้ได้เมื่อค่าเป็นตัวเลข แต่ต้องระบุขนาดหากค่าเป็นสตริง ดังนั้นในบางสถานการณ์ขนาดจึงเป็นทางเลือกในขณะที่บางสถานการณ์จำเป็นต้องใช้ และแบบสอบถามจะล้มเหลวหากไม่ได้ระบุไว้

สิ่งอื่นที่ฉันไม่ได้พิจารณา (หรือทดสอบ) คือฉันได้อ่านว่า ADODB สามารถใช้งานได้ทุกที่ที่มีไดรเวอร์ให้ ดังนั้นจึงสามารถใช้ในสมุดงาน Excel อาจเป็นไฟล์ข้อความและแหล่งข้อมูลอื่น ๆ แทนที่จะเป็นเพียงฐานข้อมูล ดังนั้นการสืบค้นแบบซิงโครนัสและอะซิงโครนัสอาจใช้งานได้เช่นกัน แต่นั่นไม่ใช่สิ่งที่ฉันกำหนดไว้เพื่อออกแบบหรือทดสอบ

ฉันขอขอบคุณคำวิจารณ์ที่สร้างสรรค์

VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
END
Attribute VB_Name = "cQueryable"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit

'Requires a refernce to the Microsoft ActiveX Data Objects 6.1 Library (or equivalent)

Private WithEvents mASyncConn As ADODB.Connection
Attribute mASyncConn.VB_VarHelpID = -1
Private mSyncConn As ADODB.Connection
Private mConn As ADODB.Connection
Private mComm As ADODB.Command
Private mSql As String
Private mProcedureAfterQuery As String
Private mAsync As Boolean
Private mConnectionString As String

Private Const mSyncExecute As Long = -1

Private Sub Class_Initialize()
    Set mComm = New ADODB.Command
    Set mConn = New ADODB.Connection
End Sub

Public Property Let Sql(value As String)
    mSql = value
End Property

Public Property Get Sql() As String
    Sql = mSql
End Property

Public Property Let ConnectionString(value As String)
    mConnectionString = value
End Property

Public Property Get ConnectionString() As String
    ConnectionString = mConnectionString
End Property

Public Property Let procedureAfterQuery(value As String)
    mProcedureAfterQuery = value
End Property

Public Property Get procedureAfterQuery() As String
    procedureAfterQuery = mProcedureAfterQuery
End Property

Public Sub createParam(pName As String, pType As DataTypeEnum, pValue As Variant, Optional pDirection As ParameterDirectionEnum = adParamInput, Optional pSize As Long = 0)
    Dim pm As ADODB.Parameter
    With mComm
       Set pm = .CreateParameter(name:=pName, Type:=pType, direction:=pDirection, value:=pValue, size:=pSize)
       .Parameters.Append pm
    End With
End Sub

Public Function SyncExecute()
    Set mSyncConn = mConn
    If connectionSuccessful Then
        With mComm
            .CommandText = mSql
            Set .ActiveConnection = mSyncConn
            Set SyncExecute = .execute(Options:=mSyncExecute)
        End With
    End If
End Function

Public Sub AsyncExecute()
    Set mASyncConn = mConn
    If connectionSuccessful Then
        With mComm
            .CommandText = mSql
            Set .ActiveConnection = mASyncConn
            .execute Options:=adAsyncExecute
        End With
    End If
End Sub

Private Function connectionSuccessful() As Boolean
    If mConn.State = adStateClosed Then
        mConn.ConnectionString = mConnectionString
    End If
    
    On Error GoTo errHandler
        If mConn.State = adStateClosed Then
            mConn.Open
        End If
    
        connectionSuccessful = (mConn.State = adStateOpen)
    On Error GoTo 0
    
    Exit Function
errHandler:
    Debug.Print "Error: Connection unsuccessful"
    connectionSuccessful = False
End Function

Private Sub mASyncConn_ExecuteComplete(ByVal RecordsAffected As Long, ByVal pError As ADODB.Error, adStatus As ADODB.EventStatusEnum, ByVal pCommand As ADODB.Command, ByVal pRecordset As ADODB.Recordset, ByVal pConnection As ADODB.Connection)
    If mProcedureAfterQuery <> "" Then
        Call Application.Run(mProcedureAfterQuery, pRecordset)
    End If
End Sub

คำตอบ

2 TinMan Aug 18 2020 at 06:27

การเชื่อมต่อฟังก์ชันส่วนตัวประสบความสำเร็จ () เป็นบูลีน

ชื่อนี้บ่งบอกว่าคุณกำลังทดสอบเพื่อดูว่าการเชื่อมต่อถูกเปิดแล้วหรือไม่เมื่อในความเป็นจริงมันถูกใช้เพื่อเปิดการเชื่อมต่อและทดสอบว่าสำเร็จ

Private Function OpenConnection() As Boolean   

ชื่อนี้บอกคุณว่าคุณกำลังเปิดการเชื่อมต่อ เนื่องจากประเภทการส่งคืนเป็นแบบบูลีนจึงเป็นเรื่องปกติที่จะถือว่าฟังก์ชันจะคืนค่าเป็น True ก็ต่อเมื่อการเชื่อมต่อสำเร็จ

การมีตัวจัดการข้อผิดพลาดหลีกเลี่ยงข้อผิดพลาดและพิมพ์ข้อความไปยังหน้าต่างทันทีนั้นเป็นผลดี ในฐานะนักพัฒนาฉันไม่ได้มองไปที่หน้าต่างทันทีโดยสัญชาตญาณสำหรับข้อความแสดงข้อผิดพลาด ในฐานะผู้ใช้ฉันจะแจ้งให้ผู้พัฒนาทราบถึงข้อความแสดงข้อผิดพลาดที่เกิดขึ้นและไม่อยู่ในจุดที่ส่งผลกระทบ เมื่อพิจารณาว่ารหัสของคุณใช้ขั้นตอนการติดต่อกลับไม่มีการรับประกันว่าจะมีข้อผิดพลาดเกิดขึ้น สิ่งเดียวที่มั่นใจได้ก็คือจะมีปัญหาบางอย่างที่เกิดขึ้น

แน่นอนคุณควรเพิ่มข้อผิดพลาดที่กำหนดเองเนื่องจากmConnectionStringไม่ได้ตั้งค่า ไม่จำเป็นต้องมีข้อความแสดงข้อผิดพลาดที่กำหนดเองสำหรับการเชื่อมต่อที่ล้มเหลว (หากคุณลบตัวจัดการข้อผิดพลาด) เนื่องจากข้อผิดพลาด ADODB จะถูกส่งไปที่จุดที่เรียกขั้นตอนนี้

สาธารณะย่อย AsyncExecute ()

พิจารณาเพิ่มข้อผิดพลาดหากไม่ได้ตั้งค่าขั้นตอนการโทรกลับ

Private Sub Class_Terminate ()

ควรใช้วิธีนี้เพื่อปิดการเชื่อมต่อ

mConn, mASyncConn และ mSyncConn

ไม่จำเป็นต้องใช้ตัวแปรการเชื่อมต่อที่แตกต่างกันสามตัวแปร คุณกำลังทำงานมากขึ้นและทำให้โค้ดสับสน การใช้ตัวแปรเช่นAsyncMode As Booleanจะให้ข้อเสนอแนะเดียวกันและลดความซับซ้อนของโค้ดทำให้อ่านง่ายขึ้น

หลักการตั้งชื่อ

การมีvalueและexecuteตัวพิมพ์เล็กจะเปลี่ยนกรณีสำหรับตัวแปรและคุณสมบัติอื่น ๆ ทั้งหมดที่มีชื่อเดียวกัน ด้วยเหตุนี้ฉันจึงใช้ Pascal Case สำหรับตัวแปรทั้งหมดที่ไม่มีคำนำหน้าบางประเภท

โรงงานของ Mathieu Guindon : การเริ่มต้นวัตถุพารามิเตอร์

การปรับปรุงอื่น ๆ ที่เป็นไปได้

กิจกรรมสาธารณะจะอนุญาตให้คุณใช้cQueryableในคลาสที่กำหนดเองอื่น ๆ

Public Event AsyncExecuteComplete(pRecordset As Recordset)

ความสามารถในการเชื่อมโยงข้อความค้นหาเข้าด้วยกันดูเหมือนจะเป็นแบบธรรมชาติ

Public Function NextQuery(Queryable AS cQueryable) AS cQueryable
   Set NextQuery = Queryable 
   Set mQueryable = Queryable 
End Function

วิธีนี้จะช่วยให้คุณสามารถเรียกใช้การสืบค้นหลายรายการตามลำดับโดยไม่จำเป็นต้องเรียกกลับหลายครั้ง

CreateTempQuery.NextQuery(FillTempTableQuery).NextQuery(UpdateEmployeesTableQuery)