VBA-Sync kodu geri bildirimi

Aug 18 2020

VBA'da eşzamansız sorgulardan yararlanma temelini soyutlamak için tasarladığım bir sınıf modülüne biraz girdi almayı umuyordum. cQueryable hem eşzamanlı hem de eşzamansız sorguları destekler. Böylece, geçici tabloları doldurmak için bir paket çağırmak gibi bir şey yapabilirsiniz. Bu eşzamanlı olarak yapılacaktır çünkü seçim sorgularınızı yürütmeden önce bunun tamamlanmasını istersiniz. Daha sonra, geçici tabloların her birinde eşzamansız olarak seçme sorgularını yürütürsünüz.

Bu kod, ADODB kitaplığındaki pek çok işlevi gerçekten soyutlamaktadır. Özelliklerimi ve yöntemlerimi, o kitaplıktaki nesnelerin mümkün olduğunda kullandıklarına benzer şekilde adlandırmaya çalıştım. ConnectionString özelliğim, ADODB.Connection nesnesindeki ile aynı şekilde adlandırılır. Ve CreateParam yöntemim, ADODB.Command nesnesinin createParameter yöntemine benzer şekilde adlandırılır.

Getirdiğim yeni prosedürlerden birkaçı sql özelliği. Bu, yürütülecek sql sorgusunu tutar (bu, komut nesnesindeki komut metniyle eşleşir). Bir diğeri ise ProcedureAfterQuery. Bu, sorgu tamamlandığında bir olay başlattıktan sonra bağlantı nesnesi tarafından çağrılacak ad prosedürünü tutmak içindir. Diğerleri SyncExecute ve AsyncExecute olup, adlarında ne yaptıklarını açıklamalıdır.

Bu ikisi hakkında unutulmaması gereken bir nokta, SyncExecute'un bir işlev, AsyncExecute'un ise bir alt yordam olmasıdır. SyncExecute'ün tamamlandığında bir kayıt kümesi döndürmesini istedim. Ancak AsyncExecute için, bir alt öğe olmasını istedim, hiçbir şey döndürdüğünü ima etmek istemedim. Bunu yapmak için benzer (ancak farklı) kod kullanıyorum. Bu yüzden KURU ilkesini ihlal ettiğimi düşünüyorum. Paylaşılan bir alt rutin prosedürü çağırmak için bu ikisini birleştirebilirim. Paylaşılan bu prosedür daha sonra daha karmaşık hale gelecektir, ancak kod en azından paylaşılacaktır. Öyle ya da böyle bir tercihim yok.

CreateParam, komut nesnesinin CreateParameter yöntemine benzer olsa da, iki fark vardır. Birincisi, argümanların sırasının farklı olmasıdır. Bunun başlıca nedeni, boyut ve yön parametrelerinin varsayılan değerlerle isteğe bağlı parametreler olarak listelenmesidir. Varsayılan değerleri yalnızca değer sayısal olduğunda kullanılabilir, ancak değer bir dizeyse boyut belirtilmelidir. Bu nedenle, belirli durumlarda boyut isteğe bağlıyken bazılarında gereklidir. Sağlanmazsa sorgu başarısız olur.

Dikkate almadığım (veya test etmediğim) diğer şeyler, ADODB'nin esasen bir sürücünün sağlanabileceği her yerde kullanılabileceğini okumam. Dolayısıyla bu, yalnızca veritabanları yerine Excel çalışma kitaplarında, belki metin dosyalarında ve diğer kaynaklarda kullanılabilir. Bu yüzden belki eşzamanlı ve eşzamansız sorgular orada da işe yarar. Ama tasarlamak ya da test etmek için yola çıktığım şey bu değil.

Yapıcı eleştiriyi takdir ediyorum.

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

Yanıtlar

2 TinMan Aug 18 2020 at 06:27

Özel Fonksiyon bağlantısı: Boolean Olarak Başarılı ()

İsim, aslında Bağlantıyı açmak ve başarılı olup olmadığını test etmek için kullanıldığında Bağlantının zaten açılıp açılmadığını test etmenizi önerir.

Private Function OpenConnection() As Boolean   

Bu isim size bir Bağlantı açtığınızı söyler. Dönüş türü Boolean olduğundan, işlevin yalnızca Bağlantı başarılı olduğunda True döndüreceğini varsaymak doğaldır.

Hata işleyicinin kaçış hatalarına sahip olması ve Anında Pencereye bir mesaj yazdırması, ters etki yaratır. Bir geliştirici olarak hata mesajları için içgüdüsel olarak Anlık Pencereye bakmıyorum. Bir kullanıcı olarak, geliştiriciye çarpma noktasında değil, hat boyunca yükseltilmiş olan hata mesajını bildireceğim. Kodunuzun geri arama prosedürleri kullandığı düşünüldüğünde, bir hatanın ortaya çıkacağına dair hiçbir garanti yoktur. Kesin olan tek şey, hattın aşağısında bir yerde sorunların olacağıdır.

Kesinlikle mConnectionStringayarlanmadıysa özel bir hata oluşturmalısınız. Başarısız bağlantı için özel bir hata iletisi gerekli değildir (hata işleyiciyi kaldırırsanız), çünkü bu yordamın çağrıldığı noktada bir ADODB hatası atılır.

Public Sub AsyncExecute ()

Geri arama prosedürü ayarlanmamışsa bir hatayı artırmayı düşünün.

Özel Alt Sınıf_ Sonlandır ()

Bağlantıyı kapatmak için bu yöntem kullanılmalıdır.

mConn, mASyncConn ve mSyncConn

Üç farklı Bağlantı değişkeni kullanmaya gerek yoktur. Daha çok iş yapıyorsun ve kodu karıştırıyorsun. Gibi bir değişken kullanmak AsyncMode As Booleansize aynı geri bildirimi verir ve kodu basitleştirerek okumayı kolaylaştırır.

Adlandırma Kuralları

Sahip valueve executeküçük harf, aynı ada sahip diğer tüm değişkenler ve özellikler için büyük / küçük harf durumunu değiştirir. Bu nedenle, bir tür öneki olmayan tüm değişkenlerim için Pascal Case kullanıyorum.

Mathieu Guindon'un Fabrikaları: Parametreli Nesne Başlatma

Diğer olası iyileştirmeler

Herkese açık bir etkinlik cQueryable, diğer özel sınıflarda kullanmanıza izin verir .

Public Event AsyncExecuteComplete(pRecordset As Recordset)

Sorguları birbirine zincirleme yeteneği doğal bir uyum gibi görünüyor.

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

Bu, birden çok geri aramaya gerek kalmadan sırayla birden çok sorgu çalıştırmanıza olanak tanır.

CreateTempQuery.NextQuery(FillTempTableQuery).NextQuery(UpdateEmployeesTableQuery)