QueryDef Object ongeldig of niet meer ingesteld.

Status
Niet open voor verdere reacties.

Gaijin66

Gebruiker
Lid geworden
25 aug 2007
Berichten
37
Access QueryDef Object ongeldig of niet meer ingesteld.

Hallo Mensen,

Ik zit met een probleem waar ik niet uitkom. Ik ben een beginnende VBA programmeur. Ik zal de situatie uitleggen.
Ik wil een database ontwerpen waarin kaarten staan van het spel Magic 2014(c). In de "Cards" tabel staan de kenmerken van de verschillende kaarten. Ik heb een tabel "Decks" waarin een samenstelling van kaarten en kenmerken van het deck staan. Deze twee tabellen hebben een veel-op-veel relatie. Een deck kan veschillende kaarten bevatten en een kaart kan in verschillende decks voorkomen. Ik heb dus een tussentabel "DeckItems" gemaakt. De primaire sleutel DeckId van "Decks" is gerelateerd aan DeckId van "DeckItems". De primaire sleutel CardId van "Cards" heeft een relatie met CardId van "DeckItems". Ik heb een formulier "Decks" met subformulier "DeckItems". Bij de gebeurtenis "Bij activeren" heb ik de volgende VBA code staan:
Code:
Private Sub Form_Activate()
    Dim DeckStats As clsDeckStats
    Dim LabelContents As String
    
    Set DeckStats = New clsDeckStats
    LabelContents = Me![StatsLabel].Caption
    DeckStats.Show LabelContents
    Set DeckStats = Nothing
End Sub

Ik heb op het formulier "Decks" een Label "StatsLabel" staan. Ik wil hierop het aantal kaarten per deck gecategoriseerd op Card Type laten verschijnen. Ik heb hiervoor een klasse module clsDeckStats ontworpen waarin onder andere een get property CreautureCards. Deze heeft de volgende code:
Code:
Public Property Get CreatureCards() As Integer
    
    Dim MagicDatabase As DAO.Database
    Dim qryDeckStats As DAO.QueryDef
    Dim QueryResults As DAO.Recordset
    Dim SQlStatement As String
    Dim Counter As Integer
    
    'Connect to Magic 2014 database
    Set MagicDatabase = CurrentDb
    
    'SQL Statement for searching for number of creatures of current deck
    SQlStatement = "SELECT DeckItems.DeckItemId, DeckItems.DeckId, DeckItems.CardId, DeckItems.Qty, Cards.[Card Type] " & _
                    "FROM Cards INNER JOIN DeckItems ON Cards.CardId = DeckItems.CardId " & _
                    "WHERE DeckId = " & Str(Forms![Decks].CurrentRecord) & " AND Cards.[Card Type].Value = ""Creature"""

    With MagicDatabase
        'Create Query and open it to look for creature cards and count it.
        Set qryDeckStats = .CreateQueryDef("DeckStatsQuery", SQlStatement)
        Set QueryResults = .OpenRecordset("DeckStatsQuery", dbOpenSnapshot)
        QueryResults.MoveFirst
        For Counter = 1 To QueryResults.EOF
            Creatures = Creatures + QueryResults.Fields("Qty")
            QueryResults.MoveNext
        Next
        .Close
        qryDeckStats.Close
        .QueryDefs.Delete qryDeckStats.Name
        Debug.Print Creatures
        CreatureCards = Creatures
    End With
    
End Property

De subroutine clsDeckStats.Initialize ziet er als volgt uit:
Code:
Private Sub DeckStats_Initialize()
    Dim MagicDatabase As DAO.Database
    Dim qryDeckStats As DAO.QueryDef
    
    Creatures = 0
    Sorceries = 0
    Instants = 0
    Enchantments = 0
    Artifacts = 0
    Lands = 0
    Total = 0
    
    Set MagicDatabase = CurrentDb
    'Delete existing query
    MagicDatabase.QueryDefs.Delete qryDeckStats.Name
End Sub

clsDeckStats.Show bevat de volgende code:
Code:
Public Sub Show(ByRef StatsView As String)
    
    StatsView = "Stats:" & vbCrLf & vbCrLf & _
                "Creature Cards:" & vbTab & vbTab & Str(CreatureCards) & vbCrLf & _
                "Sorcery Cards:" & vbTab & vbTab & Str(SorceryCards) & vbCrLf & _
                "Instant Cards:" & vbTab & vbTab & Str(InstantCards) & vbCrLf & _
                "Enchantment Cards:" & vbTab & Str(EnchantmentCards) & vbCrLf & _
                "Artifact Cards:" & vbTab & vbTab & Str(ArtifactCards) & vbCrLf & _
                "Land Cards:" & vbTab & vbTab & vbTab & Str(LandCards) & vbCrLf & _
                "Other Cards:" & vbTab & vbTab & Str(OtherCards) & vbCrLf & _
                "Cards:" & vbTab & vbTab & vbTab & vbTab & Str(TotalCards) & vbCrLf
    Debug.Print StatsView
End Sub

Als ik het formulier "Decks" open krijg ik de foutmelding: 3420 "Object ongeldig of niet meer ingesteld". Ik gebruik trouwens Access 2007. Wat doe ik fout en wie wil mij helpen? Bij voorbaat dank.
 
Laatst bewerkt:
waar krijg je precies het probleem? bij "magicdatabase.querydefs.delete"?
 
Code:
Private Sub Form_Activate()
    Dim DeckStats As clsDeckStats
    Dim LabelContents As String
    
    Set DeckStats = New clsDeckStats
    LabelContents = Me![StatsLabel].Caption
    DeckStats.Show LabelContents
    Set DeckStats = Nothing
End Sub

De foutopsporing stopt hier:
Code:
    LabelContents = Me![StatsLabel].Caption

De query "DeckStatsQuery" wordt wel aangemaakt, maar niet verwijderd.
 
Tenzij de loop dan ergens anders vastloopt lijkt mij het probleem dan te zitten in [statslabel], Heb je al geprobeerd even deze regel op 'remark' te zetten en kijken wat er vervolgens gebeurt? Maar dan gaan we al snel naar normale debugging toe. Loopt de code misschien te vroeg? Of mogelijk te vaak.
 
Of vergeet voor het moment de variabele LabelContents, want die heb je helemaal niet nodig:
Code:
    Set DeckStats = New clsDeckStats
    DeckStats.Show Me.StatsLabel.Caption
    Set DeckStats = Nothing
Dan zou DeckStats in ieder geval kunnen openen. Ik neem aan dat clsDecStats een klasse is? En dat die klopt? Want daar zie ik de code niet van.
 
Tenzij de loop dan ergens anders vastloopt lijkt mij het probleem dan te zitten in [statslabel], Heb je al geprobeerd even deze regel op 'remark' te zetten en kijken wat er vervolgens gebeurt? Maar dan gaan we al snel naar normale debugging toe. Loopt de code misschien te vroeg? Of mogelijk te vaak.

Hoe doe ik dat?
 
Of vergeet voor het moment de variabele LabelContents, want die heb je helemaal niet nodig:
Code:
    Set DeckStats = New clsDeckStats
    DeckStats.Show Me.StatsLabel.Caption
    Set DeckStats = Nothing
Dan zou DeckStats in ieder geval kunnen openen. Ik neem aan dat clsDecStats een klasse is? En dat die klopt? Want daar zie ik de code niet van.
De property CreatureCards, Initialize en Show zijn eigenschap en methoden van de klasse clsDeckStats. Over die variabele LabelContents heb je gelijk. Die had ik eerst ook niet, maar ik was zoekende naar de oorzaak van het probleem.
Als ik het goed van jou begrijp moet ik StatsLabel niet benaderen als een collectie.
 
Laatst bewerkt:
Hoeft niet als je vanuit een formulier naar een object verwijst. Maar als we niet de volledige code hebben, is het lastig te zien waar een fout zit. En aangezien je fout al gelijk in het begin optreedt, zou ik eerst controleren of de Caption wel klopt. Maar een bijschrift uitlezen is nou niet bepaald het moeilijkste in VBA ;)
Post anders een db met alle code en formulieren. Werkt in ieder geval voor ons een stuk sneller. En om het draadje leesbaar te houden, verzoek ik je vriendelijk om niet complete berichten te quooten; nergens voor nodig :)
 
Je hebt helemaal gelijk, Octafish. Mijn excuses. Mijn PC voert nu een schijfcontrole uit. Zodra ik er bij kan zal ik de db posten. Kan dat in een zip-bestand?
 
Dat is uiteraard geen probleem. Sterker nog: de enige manier om een db te posten, want HelpMij doet moeilijk over accdb en mdb bestanden. Eventueel, als het bestand te groot is, kun je met WinRar nog deelbestanden maken van 100kb, of hem uploaden naar een fileshare zoals mijnbestand.nl. In het laatste geval hoef je 'm ook niet te zippen.
 
Hier kun je de db downloaden. Ik hoop dat het goed gegaan is.

Ik heb trouwens mijn code aangepast naar:
Code:
Private Sub Form_Activate()
    Dim DeckStats As clsDeckStats
    
    Set DeckStats = New clsDeckStats
    DeckStats.Show Me.StatsLabel.Caption
    Set DeckStats = Nothing
End Sub

Nu stopt foutopsporing bij:
Code:
    DeckStats.Show Me.StatsLabel.Caption
 
Laatst bewerkt:
Er gaat nogal wat fout in je db, dus ik heb de code overal aangepast. Omdat de fout zo'n beetje overal hetzelfde was, laat ik er één zien. Dat je db zo groot is komt natuurlijk doordat je de plaatjes er in opslaat. Erg ongelukkige handeling vind ik zelf; je kunt ze beter buiten de db laten en met tekstvelden werken. Houdt de db kleiner, en het beheer van je plaatjes ook. Maar daar zit het probleem niet, dus dat is een zijsprong ;)
De code zou ik zo doen:

Code:
Dim dB As DAO.Database
Dim qDef As DAO.QueryDef
Dim qResult As DAO.Recordset
Dim strSQL As String
Dim Counter As Integer

De volgende variabelen kun je vervangen door één variabele. Scheelt weer declareren :).

Code:
Private Creatures As Integer
Private Sorceries As Integer
Private Instants As Integer
Private Enchantments As Integer
Private Artifacts As Integer
Private Lands As Integer
Private Others As Integer
Private Total As Integer
'Wordt: 
Private iValue As Integer

En de procedures zou ik zo doen:
Code:
Public Property Get CreatureCards() As Integer
        iValue=0
    'Connect to Magic 2014 database
    Set dB = CurrentDb
    'SQL Statement for searching for number of creatures of current deck
    strSQL = "SELECT DeckItems.DeckItemId, DeckItems.DeckId, DeckItems.CardId, DeckItems.Qty, Cards.[Card Type] " & _
                    "FROM Cards INNER JOIN DeckItems ON Cards.CardId = DeckItems.CardId " & _
                    "WHERE DeckId = " & Str(Forms![Decks].CurrentRecord) & " AND Cards.[Card Type].Value = ""Creature"""

    With dB
        'Create Query and open it to look for creature cards and count it.
        Set qDef = .QueryDefs("DeckStatsQuery")
        qDef.SQL = strSQL
        Set qResult = .OpenRecordset("DeckStatsQuery", dbOpenSnapshot)
        With qResult
            If .RecordCount > 0 Then
                For Counter = 0 To .RecordCount - 1
                    iValue = iValue + .Fields("Qty")
                    .MoveNext
                Next
            End If
            .Close
        End With
        qDef.Close
        CreatureCards = iValue 
    End With
    
End Property
Jij gooit steeds de querydef weg, en maakt hem opnieuw aan. Nergens voor nodig, laten staan dus en alleen de SQL aanpassen.
De echte fouten zaten in het ontbreken van een check op lege recordsets (If .RecordCount > 0 Then) en het niet goed doorlopen ervan (For Counter = 0 To .RecordCount - 1). En dan gaat-ie natuurlijk nooit optellen :).
 
Laatst bewerkt:
Dank je wel Octafish, voor je tijd en je moeite. Ik ga er mee aan de slag. Ik laat het weten als het werkt en dan zet ik de status ook op opgelost.
 
Nog even 2 opmerkingen:
1. als je je eigen variabelenamen houdt, let er dan op dat je de juiste waarden toekent aan de objecten. Dus:
Code:
Instants = Instants + .Fields("Qty")
InstantCards = Instants
en niet:
Code:
Instants = Instants + .Fields("Qty")
InstantCards = Enchantments
Wat je bij een aantal functies tegenkomt. Waarschijnlijk een resultaat van Knippen en Plakken :).

2. Als je variabelen declareert, doe je dat meestal om het jezelf makkelijker te maken, niet moeilijker. Dus:
Code:
 Dim db As DAO.Database
Set db = CurrentDb()
is logisch, maar
Code:
 Dim MagicDatabase As DAO.Database
Set MagicDatabase = CurrentDb()
?
De variabelenaam is nu langer dan de objectnaam! Wat is daar nu het nut van? Je hebt alleen maar meer typwerk!
 
Klopt. Was inderdaad een resultaat van knippen en plakken. Het tweede heb ik voor de leesbaarheid. Als ik in de toekomst terug kijk zie ik direct waar de variabele voor word gebruikt en zo veel extra typwerk is het niet.

Ik heb het op jouw advies aangepast. Ik laat DeckStatsQuery ook staan. Nu krijg ik de foutmelding: 3012 Het object DeckStatsQuery bestaat al. Waar en hoe moet ik de code aanpassen?
 
Laatst bewerkt:
Je moet in elke Geen idee waarom je de foutmelding krijgt, waarschijnlijk staat er nog ergens een code die de query maakt, en die moet dan weg. Overigens zou ik het dus totaal anders doen, met veel minder code die ook nog eens veel makkelijker te onderhouden is. Die is dermate klein, dat ik 'm nog kan posten ook :)
Op het formulier krijg je dan:
Code:
Private Sub Form_Current()
Dim i As Integer

    'Roep de procedure aan die de kaarten telt.
    TelKaarten (Me.CurrentRecord)

    'String maken voor de samenvatting
    StatsView = "Stats:" & vbCrLf & vbCrLf
    For i = 1 To 8
        StatsView = StatsView & arrKaarten(i, 1) & vbTab & vbTab & arrKaarten(i, 2) & vbLf
    Next i
    MsgBox StatsView

End Sub

En ik gebruik dan een functie op een normale module, dus geen klassemodule.

Code:
Option Compare Database
Option Base 1
Public arrKaarten(8, 2) As String, arrKaart As Variant
Declaratie van de variabelen

Code:
Function TelKaarten(curRecord As Long)
Dim i As Integer
    arrKaart = Array("Creature", "Sorcery", "Instant", "Enchantment", "Artifact", "Land", "Total", "Other") 'Variabele vullen met de namen van de kaarten die je wilt checken.
    For i = 1 To 8
        arrKaarten(i, 1) = arrKaart(i)      'de matrix waarin de waarden opgeslagen worden vullen met de veldnamen uit de array arrKaart.
    Next i
    'Connect to Magic 2014 database
    Set dB = CurrentDb
    
For i = 1 To 8     'Met een lus door alle veldnamen lopen. Er is onderscheid tussen de 1e 6, Total en Other. Dus ....
    Select Case i     '... Met een Select Case de verschillende queries opbouwen die nodig zijn.
        Case 1 To 6      'De eerste 6 komen uit de tabel op basis van RecordID en [Card Type]. Gaat naar sub Kaartlezen.
            strSQL = "SELECT DeckItems.DeckItemId, DeckItems.DeckId, DeckItems.CardId, DeckItems.Qty, Cards.[Card Type] " & _
                "FROM Cards INNER JOIN DeckItems ON Cards.CardId = DeckItems.CardId " & _
                "WHERE DeckId = " & curRecord & " AND Cards.[Card Type].Value = '" & arrKaarten(i, 1) & "'"
            GoSub KaartLezen
        Case 7     'Case 7 haalt het totaalplaatje op. Gaat naar sub Kaartlezen.
            strSQL = "SELECT DeckItems.DeckItemId, DeckItems.DeckId, DeckItems.CardId, DeckItems.Qty, Cards.[Card Type] " _
                & "FROM Cards INNER JOIN DeckItems ON Cards.CardId = DeckItems.CardId WHERE DeckId = " & curRecord
            GoSub KaartLezen
        Case 8     'Rekent het verschil uit. Gebruikt daarom een andere subprocedure.
            GoSub KaartOther
    End Select
Next i
Exit Function

KaartLezen:
    With dB
        'Create Query and open it to look for creature cards and count it.
        Set qDef = .QueryDefs("DeckStatsQuery")
        qDef.SQL = strSQL
        Set qResult = .OpenRecordset("DeckStatsQuery", dbOpenSnapshot)
        With qResult
            If .RecordCount > 0 Then
                For Counter = 0 To .RecordCount - 1      'Loopt door alle records van de query en vult de variabele arrKaarten(i, 2) met de juiste waarde.
                    'De variabele arrKaarten is van het type Text, dus onderscheid tussen eerste veld vullen (variabele is nog leeg) of optellen met vorige waarde.
                    If Counter = 0 Then arrKaarten(i, 2) = .Fields("Qty") Else: arrKaarten(i, 2) = CStr(Nz(arrKaarten(i, 2), 0) + CInt(.Fields("Qty")))
                    .MoveNext
                Next
            Else
                arrKaarten(i, 2) = 0
            End If
            .Close
        End With
    End With
    Return
    
KaartOther:
    Dim SelectedTypes As Integer
    SelectedTypes = CreatureCards + SorceryCards + InstantCards + EnchantmentCards + ArtifactCards + LandCards
    If SelectedTypes < TotalCards Then arrKaarten(i, 2) = TotalCards - SelectedTypes Else: arrKaarten(i, 2) = 0
Return

End Function

En zo kun je met een relatief kleine procedure alles doorlopen wat je nodig hebt. En je hoeft dus maar op één plek iets te wijzigen als dat nodig is.
 
Laatst bewerkt:
Octafish, je bent geweldig. Ik ga jouw code gebruiken. Ik ga er van uit dat het werkt. Dan sluit ik dit draadje en zet de status op opgelost.
 
Als je het niet werkend krijgt, kun je kijken in de werkende versie. Heb wel je plaatjes weggegooid :) Dus zonder de bijlagevelden...
 

Bijlagen

  • Magic 2014 v2 klein.rar
    195,3 KB · Weergaven: 23
Super. Heb ik veel aan.

Ik zie dat jouw db ook niet helemaal goed loopt. Total Cards moet 60 uit komen en geeft nu 25 aan.
 
Laatst bewerkt:
Ik heb niet naar de juistheid van de gegevens gekeken; alleen of de procedure het doet of niet. En daarbij jouw code dus 'vertaalt' naar een algemene variant.
 
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan