Neuigkeiten:

Ist euer Problem gelöst, dann bitte den Knopf "Thema gelöst" drücken!

Mobiles Hauptmenü

Bei Eingabe in gebundenes Textfeld wird Feld in der Abfrage NICHT aktualisiert

Begonnen von KonradR, Januar 11, 2025, 09:26:19

⏪ vorheriges - nächstes ⏩

KonradR

Hallo liebe Accessfreunde,

ich habe ein Pop-up-Formular mit mehreren gebundenen Textfeldern. Die Datensatzquelle des Pop-Up-Formulars wird anhand der Auswahl eines Kombinationsfeldes vom vorherigen Einzelformular gefiltert. Wenn ich jetzt im Pop-Up-Formular in das Textfeld "txtZugabeMenge" einen Wert eingebe, wird dieser in der verknüpften Datensatzquelle bzw. Abfrage nicht aktualisiert. Wenn ich den Wert jedoch in dem Feld in der Abfrage eingebe, wird dieser im Pop-Up-Formular sofort aktualisiert. Wenn ich das Pop-Up-Formular schließe und es anschließend wieder öffne, steht der neu eingegebene Wert im o.g. Textfeld und die Abfrage ist aktualisiert. Wenn ich nach der Eingabe im o.g. Textfeld auf dem Pop-Up-Formular in der Abfrage auf "alle aktualisieren" klicke, ändert sich der eingegebene Wert auch nicht. Habt ihr eine Idee, woran das liegen kann, dass die Aktualisierung der Daten nur nach dem Schließen und anschließenden Öffnen des Pop-Up-Formulars funktioniert?

MzKlMu

Hallo,
das Formular (bzw. die Datenquelle) muss mit
Me.Requery (VBA) aktualisiert werden.
Gruß Klaus

Knobbi38

Hallo Konrad,

was meinst du denn mit
Zitat... in der verknüpften Datensatzquelle bzw. Abfrage
?

Bevor andere Objekten auf deine Eingabe zugreifen können, muß diese natürlich erst in die DB geschrieben worden sein. Beim Schließen eines Formulars passiert das automatisch, ansonsten mußt du das händisch per Code veranlasssen.


Beaker s.a.

Genau, am Einfachsten direkt nach der Eingabe
Private txtZugabeMenge_AfterUpdate()
    Me.Dirty = False
End Sub
Alles, was geschieht, geschieht. - Alles, was während seines Geschehens etwas anderes geschehen lässt, lässt etwas anderes geschehen. - Alles, was sich selbst im Zuge seines Geschehens erneut geschehen lässt, geschieht erneut. - Allerdings tut es das nicht unbedingt in chronologischer Reihenfolge.
(Douglas Adams, Mostly Harmless)

Bitsqueezer

Hallo,

eine der schönen Automatismus-Funktionen von Access ist, daß ein Undo eingebaut ist.
Es ist eine ätzende Methode moderner Software (wie z.B. in den Windows-Systemeinstellungen), nach einer Änderung sofort alles zu speichern. Wenn man auf einer Einstellungsseite (oder eben einem Datensatz) diverse, ungespeicherte Einstellungen hat, und einem dann auffällt, das man das doch nicht speichern will, kann man eben in Windows (früher) einfach nicht speichern bzw. in Access ESC drücken, einmal für das aktuelle Feld, zweimal für den ganzen Datensatz. Und dann ist auf der DB nix passiert.

Das sofortige Speichern verhindert die Undo-Möglichkeit, man muß dann im Zweifelsfall alles manuell zurückdrehen, wenn man denn noch weiß, was vorher dringestanden hat in den Feldern.
Ganz nebenbei verhindert man so auch, eine datensatzweise Validierung durchführen zu können mit Form_BeforeUpdate. Oft sind Daten erst im Zusammenhang mit anderen Feldern gültig oder nicht und das kann man hier sehr gut austesten und den Datensatz speichern oder ablehnen.

Wenn man aber nach jedem Feld den Datensatz speichert, ist das nicht möglich und führt dann z.B. dazu, daß andere Felder als falsch markiert wurden. Etwa hat man den Vornamen eingegeben, wird sofort der Nachname als falsch (weil fehlend) markiert, obwohl man den noch gar nicht eingegeben hat. Diesen Blödsinn sieht man leider mittlerweile auch auf etlichen Formular-Websites. Es genügt, Felder als notwendig zu bezeichnen und erst dann als Fehler anzuzeigen, wenn man versucht zu speichern. Datensatzvalidierung eben.

Gruß

Christian

KonradR

Zitat von: MzKlMu am Januar 11, 2025, 11:28:25Hallo,
das Formular (bzw. die Datenquelle) muss mit
Me.Requery (VBA) aktualisiert werden.
Danke, das war die Lösung. Die Aktualisierung wird an die Abfrage weitergegeben.

KonradR

Zitat von: knobbi38 am Januar 11, 2025, 12:03:24was meinst du denn mit
Damit meine ich, dass das Formular eine Abfrage als Datensatzquelle hat und das diese nicht aktualisiert wird, wenn ich in dem benannten Textfeld einen anderen Wert reinschreibe.

Zitat von: knobbi38 am Januar 11, 2025, 12:03:24Bevor andere Objekten auf deine Eingabe zugreifen können, muß diese natürlich erst in die DB geschrieben worden sein. Beim Schließen eines Formulars passiert das automatisch, ansonsten mußt du das händisch per Code veranlasssen.
Das ist wahrscheinlich das von Klaus erwähnte Me.Requery.

KonradR

Zitat von: Beaker s.a. am Januar 11, 2025, 12:05:11Genau, am Einfachsten direkt nach der Eingabe
Private txtZugabeMenge_AfterUpdate()
    Me.Dirty = False
End Sub

Danke, dass funktioniert auch.

KonradR

Zitat von: Bitsqueezer am Januar 11, 2025, 14:57:45Ganz nebenbei verhindert man so auch, eine datensatzweise Validierung durchführen zu können mit Form_BeforeUpdate.
Ist das jetzt gut oder schlecht? Denn aktuell habe ich ein neues Problem. Ich habe nämlich eine Datensatzvalidierung im
Form_BeforeUpdate Ereignis, weil ich zwei Felder auf korrekte Eingabe prüfen will, bevor der gewünschte Vorgang, den ich per VBA programmiert habe beginnt. Die Fehlermeldung heißt: "Laufzeitfehler '2185': Sie können auf die Eigenschaften oder Methoden eines Steuerelements nur verweisen, wenn das Steuerelement den Fokus hat." Wenn ich sämtlichen Code im Form_BeforeUpdate Ereignis auskommentiere funktioniert es.

Bitsqueezer

Hallo,

also ich persönlich sage, es ist schlecht, wenn man jede Änderung sofort speichert. Weil man Undo verhindert und weil Form_BeforeUpdate u.a. dazu da ist, alle Felder im Zusammenhang testen zu können.

Deine Fehlermeldung bedeutet vermutlich, daß Du auf die Eigenschaft "Text" verweist, die nur gültig ist, solange ein Control den Fokus hat. Das ist der Inhalt der Eingabe während der Änderung, ansonsten ist es "Value".

Aber dazu müßtest Du schon mal den Code aus Form_BeforeUpdate zeigen.
Klar, wenn man Code deaktiviert, dann gibt es ja auch nichts, was "nicht funktionieren" könnte.

Gruß

Christian

KonradR

Hallo Bitsqueezer,

Zitat von: Bitsqueezer am Januar 11, 2025, 16:48:36und weil Form_BeforeUpdate u.a. dazu da ist, alle Felder im Zusammenhang testen zu können.
Deswegen habe ich ja das Form_BeforeUpdate Ereignis genutzt.

Zitat von: Bitsqueezer am Januar 11, 2025, 16:48:36Deine Fehlermeldung bedeutet vermutlich, daß Du auf die Eigenschaft "Text" verweist, die nur gültig ist, solange ein Control den Fokus hat. Das ist der Inhalt der Eingabe während der Änderung, ansonsten ist es "Value".
Wow. Du hast meinen Code noch nicht gesehen und weist, wo der Fehler liegt. Exakt an dieser Stelle gibt der Kompiler die Fehlermeldung aus. Hier mein Code, der etwas länger geworden ist:
Private Sub Form_BeforeUpdate(Cancel As Integer)
'MsgBox "Form_BeforeUpdate(Cancel As Integer)"
'_______________________________________________________________________
'EINGABEPRÜFUNG VON STEUERELEMENT txtZugabeMenge UND cboZugabeEinheit
    Select Case True
        Case IsNull(Me.txtZugabeMenge.Value) And IsNull(Me.cboZugabeEinheit.Value)
            MsgBox "Es sind Leerzeichen in den Textfeldern ""Zugabemenge"" und ""Zugabeeinheit""" & vbCrLf & _
            "Bitte in beide Felder einen Wert eintragen."
            Cancel = True
        Case IsNull(Me.txtZugabeMenge.Value) And Me.cboZugabeEinheit.Value <> ""
            MsgBox "Es sind Leerzeichen im Textfeld ""Zugabemenge"". Bitte einen Wert eintragen."
            Cancel = True
        Case IsNull(Me.txtZugabeMenge.Value) And Not IsNull(Me.cboZugabeEinheit.Value)
            MsgBox "Bitte eine Zugabemenge eingeben"
            Cancel = True
        Case Me.txtZugabeMenge.Value = 0 And IsNull(Me.cboZugabeEinheit.Value)
            MsgBox "Bitte eine Zugabemenge > 0 und eine Zugabeinheit eingeben"
            Cancel = True
        Case Me.txtZugabeMenge.Value = 0 And Not IsNull(Me.cboZugabeEinheit.Value)
            MsgBox "Bitte eine Zugabemenge > 0 eingeben"
            Cancel = True
'        Case Not IsNull(Me.txtZugabeMenge.Value) And IsNull(Me.cboZugabeEinheit.Value): MsgBox "Bitte eine Zugabeeinheit eingeben"
            Cancel = True
        Case Not IsNull(Me.txtZugabeMenge.Value) And Not IsNull(Me.cboZugabeEinheit.Value)
    Dim ZEWert As Integer                   'Variable f. Wert des Feldes cboZugabeEinheit deklariern
    Dim rcsZugabeEinheit As DAO.Recordset   'Variable f. Recordset m.d. Tabelle tblRezeptGewicht deklariern
    Dim rcsEinheiten As DAO.Recordset       'Variable f. Recordset m.d. Tabelle tblGewichtsEinheitenName deklariern
    Dim ZEText As String                    'Variable f. Text des Feldes ZugabeEinheit deklariern
    Dim RezIDRef As Integer                 'Variable f. Zahl die in txtRezepID drin steht deklariern
    Dim db As DAO.Database              '"db" als Variable für eine Datenbank aus der DAO Bibliothek deklarieren - aktuell keine Verwendung
    Dim lngZutatSammlID As Long         '"lngZutatSammlID" als Variable für das 1. Schlüsselfeld des zu kopierenden DS deklarieren (Acces selbst vergeben lassen weil Autowert & sonst doppelt & Fehlermeldung)
    Dim lngZutatSammlIDNeu As Long      '"lngZutatSammlIDNeu" als leere Variable zur Übergabe der DS-Nummer deklarieren auf den nach der Akualisierung gesprungen werden soll
    Dim lngZutatSammlLaMaZIDRef As Long '"lngZutatSammlIDNeu" als Variable für das 2. Schlüssslfeld des zu kopierenden DS deklarieren (Acces selbst vergeben lassen weil Autowert & sonst doppelt)
    Dim lngZutatSammlRezepIDRef As Long 'Variable als Übergabe für den Wert des Fremdschlüsselfeldes ZutatSammlRezepIDRef (damit alle Zutaten des Rezepts aufgelistet werden)
    Dim lngZutatSammlRezepIDRef2 As Long 'Variable als Übergabe für den Wert des Fremdschlüsselfeldes für ZutatSammlRezepIDRef (damit alle Zutaten in den Zielrecordset kopiert werden)
    Dim SQLRcsZiel As String            '"SQL String für den Inhalt des Recordsets für das 2. Unterformular in "sfrmPopRezeptAlsZutatUnter2"
    Dim rcsRezeptZutatenGesamt As DAO.Recordset
    Dim rcsRezeptZutatenGpEinzeln As DAO.Recordset
    Dim rcsRezeptZutatenGpEinzelnGefiltert As DAO.Recordset
    Dim fld As Field
    Dim lngZutatNr As Long
    Dim rcsZutatStammName As DAO.Recordset
    Dim lngZutatSammlIDUfo1 As Integer         'Variable für den Wert 1 für das Textfeld "txtRotAn" deklarieren. Damit mit bedingter Formatierung der Hintergrund aller STE rot gefärbt
                                            'werden kann

        ZEWert = Forms("frmPopRezeptAlsZutat").Controls("cboZugabeEinheit").Value   'Variablen f. ZEWert den Wert zuweisen
        ZEText = Forms("frmPopRezeptAlsZutat").Controls("cboZugabeEinheit").Text    'Variablen f. ZEText den Wert zuweisen
        RezIDRef = Forms("frmPopRezeptAlsZutat").Controls("txtRezepID").Value       'Variablen f. RezIDRef den Wert zuweisen

        Set rcsZugabeEinheit = CurrentDb.OpenRecordset("SELECT * FROM tblRezeptGewicht WHERE rezgeEhIDRef = " & ZEWert & " AND rezgeRezepIDRef = " & RezIDRef, dbOpenDynaset)
        'Recordset der Variablen rcsZugabeEinheit zuweisen: Alle Felder aus der Tabelle tblRezeptGewicht, bei denen der Wert aus dem Feld cboZugabeEinheit mit dem
        'Tabellenfeld rezgeEhIDRef (Feld f. ID d. Fremdschlüsselfeldes f.d. Einheit) übereinstimmt UND
        'der Fremdschlüssel zur tblRezept mit dem Wert in txtRezepID (Variable: RezIDRef) übereinstimmt
        'kurz: alle DS zu der ausgewählten Einheit im cbo cboZugabeEinheit für das Rezept mit der Nummer aus dem Textfeld txtRezepID im RS auflisten
        'kurz2: rcsZugabeEinheit ist der Recordset für die Sammlung der Gewichte der einzelnen Rezepteinheiten des bestimmten Rezepts
        Set rcsEinheiten = CurrentDb.OpenRecordset("SELECT * FROM tblGewichtsEinheitenName WHERE GweNameID = " & ZEWert, dbOpenDynaset)
        'Recordset der Variablen rcsEinheiten zuweisen: alle Felder der Tabelle tblGewichtsEinheitenName bei denen das Feld GweNameID mit dem Wert des Textfeldes cboZugabeEinheit
        '(Variable: ZEWert) übereinstimmt

'______________________________________________________________________________________________________________

Der Fehler tritt an der Zeile:
ZEText = Forms("frmPopRezeptAlsZutat").Controls("cboZugabeEinheit").Text    'Variablen f. ZEText den Wert zuweisenauf. Ich habe nicht den kompletten Kode eingefügt, weil ich sonst über die 20.000 Zeichen für einen Beitrag komme.

Knobbi38

Hallo Konrad,
ZitatDamit meine ich, dass das Formular eine Abfrage als Datensatzquelle hat und das diese nicht aktualisiert wird, wenn ich in dem benannten Textfeld einen anderen Wert reinschreibe.
das gibt für mich keinen Sinn. Wieso sollte sich einen Abfrage aktualisieren müssen, wenn ein Textfeld geändert wird?

Da passt etwas mit der Programmlogik nicht und auch, was Christian schon beschrieben hat, sollte man berücksichtigen.

Wenn das dein Code für Form_BeforeUpdate ist, solltest du das Formular und deinen Workflow nochmal überdenken. Was soll das ganze Gedöns mit den Deklarationen und Recordsets? Da ist mehr im Argen, als nur die Frage, ob und wann gespeichert werden soll.

Btw.:
ZitatZEText = Forms("frmPopRezeptAlsZutat").Controls("cboZugabeEinheit").Text
Solche Zuweisungen sollten grundsätzlich vermieden werden, denn die Werte können per Openargs beim Öffnen des Popups übergeben werden. Mal abgesehen davon, daß die .Text Eigenschaft hier falsch verwendet wird. Bis auf wenige Ausnahmen wird in Access immer die .Value Eigenschaft verwendet.

ZitatDim lngZutatSammlIDUfo1 As Integer
Ist das ein Typo? Wenn schon Präfixe verwendet werden, sollten sie mit der Deklaration auch übereinstimmen.


Bitsqueezer

Hallo,

also zu dem Code hätte ich auch noch so einige Anmerkungen, die die von Ulrich noch ergänzen.

  • Text vs. Value hatten wir ja schon. Die Value-Eigenschaft ist normalerweise die Default-Eigenschaft, daher kann man sie auch einfach weglassen. In seltenen Fällen kann man schon mal etwas anderes bekommen als den Value, z.B. beim Zugriff auf die Fields eines Recordsets, je nach Art des Zugriffs erhältst Du dann das Feld selbst und nicht dessen Wert. Also wenn Du sichergehen möchtest, ist ".Value" zu schreiben, zumindest nicht falsch.
  • wenn ich Dir einen Tip zu Usability geben darf: Form_BeforeUpdate sollte der "Fehlersammler" sein. Nicht der Code, der den User zur Weißglut nervt:
    • Select Case kann immer nur ein True behandeln, beim ersten Case, das zutrifft, ist Ende (das ist nicht in allen Programmiersprachen so, aber in VBA)
    • wenn man mehr als einen Fehler testen will, dann ist es besser, einzelne Ifs zu schreiben (die dann alle durchgegangen werden), und dann je aufgetretenem Fehler eine String-Variable zu erweitern, in der die Fehler gesammelt werden. Dann kann man am Ende eine gesammelte Fehlermeldung ausgeben.
    • in Deiner aktuellen Version bekommt der User nur den ersten Fehler per Messagebox, er behebt ihn, versucht erneut zu speichern und bekommt den 2. Fehler usw., im schlimmsten Fall alle nacheinander. Das nervt gewaltig.
  • Test auf leeres Feld: Ich empfehle Dir, statt "IsNull" besser Nz zu verwenden. Mit Nz kannst Du einen Austauschwert für NULL angeben, denn ein optisch leeres Feld muß nicht zwingend NULL sein, es kann auch ein Leerstring sein. Mit Nz ist "" immer der Standardaustauschwert, somit kannst Du testen "If Nz(Feld) = "" Then" und hast immer beide Varianten abgesichert. Der Rest ist von den Einstellungen des Feldes im Tabellendesign abhängig (ob Leereingaben zulässig sind).
  • Integer: Sei vorsichtig mit der Verwendung von Integern. In anderen Programmiersprachen ist das ein 32Bit-Wert, in VBA ist es nur 16Bit. Das fällt bei Speicherung von ID-Werten erst mal nicht auf, bis Du über die +-Grenze von 32767 hinauskommst, was für IDs nicht allzuviel ist. Es gibt nahezu nie eine Einsatznotwendigkeit für Integer und in Zeiten von Gigabyte-RAM ist auch kein Speichersparen mehr notwendig. Daher am besten immer Long verwenden, dann bist Du im Allgemeinen immer auf der sicheren Seite (und ID-Felder von Tabellen können keine höheren Werte produzieren, außer im seltenen Fall, daß es ein Bigint ist, was in Access auch noch nicht so lange gibt).
  • da das nicht der gesamte Code ist, kann man nur ahnen, was da noch alles kommen mag. Bei so vielen "Dim"s wird man aber schon skeptisch. Wenn Du schon selbst gesehen hast, daß da welche gar nicht gebraucht werden, kommentiere die Zeile am besten aus, dann kannst Du sie später auch gleich ganz rausnehmen
  • Zugriff auf Felder: Die maximal umständlichste und dazu noch vom Compiler nicht prüfbare Syntax mit Zugriff per Namen in Strings. Da "frmPopRezeptAlsZutat" vermutlich das Formular ist, in dem Du den Code stehen hast, kannst Du auch ganz einfach "Me.cboZugabeEinheit" schreiben. Und das kann der Compiler dann auch prüfen (ob es das Control auch gibt).
  • Zuweisung an eine String-Variable: Bitte beachte, daß außer "Variant" kein Variablentyp mit NULL umgehen kann.
  • Wieso ist die Fehlermeldung zu: "IsNull(Me.txtZugabeMenge.Value) And IsNull(Me.cboZugabeEinheit.Value)", daß es Leerzeichen in den Feldern gibt? NULL steht für "Nichts".
  • Wozu die Recordsets verwendet werden, schreibst Du nicht. Generell gilt:
    • Auf "SELECT *" verzichten: Immer die genaue Feldliste angeben, die Du wirklich haben willst. Gründe dafür findest Du mit Google etc. leicht massenhaft. Zu oft aufgeschrieben, um es zum 1000.Mal zu wiederholen.
    • Möglichst auf zusammengesetzte SQL-Strings verzichten. Dazu mal unter "SQL Injection" suchen. Das trifft zwar im Fall von Access nicht zu, da man in Access keine SQL-Batches schreiben kann, aber besser gleich richtig angewöhnen.

Da möchte ich lieber nicht wissen, wie der übrige Code wohl aussieht... ;)
Natürlich hat sicher jedes Modul, wie es jeder macht, "Option Explicit" als erste Zeile und Du nutzt ja auch sicher immer den Kompiler..... oder?

Gruß

Christian


KonradR

Hallo knobbi38,

Zitat von: knobbi38 am Januar 11, 2025, 20:21:56Hallo Konrad,
ZitatDamit meine ich, dass das Formular eine Abfrage als Datensatzquelle hat und das diese nicht aktualisiert wird, wenn ich in dem benannten Textfeld einen anderen Wert reinschreibe.
das gibt für mich keinen Sinn. Wieso sollte sich einen Abfrage aktualisieren müssen, wenn ein Textfeld geändert wird?
Weil aufgrund der Eingabe der Daten im Textfeld, die gerade eingegeben wurden, die Abfrage geändert werden soll und damit Berechnungen in der Abfrage neu berechnet werden sollen. Die berechneten Werte will ich weiterverwenden. Wenn die Anpassung der Abfrage erst nach dem Schließen des Formulars erfolgt, ist die Berechnung auf Grundlage der Werte passiert, die vorher im Formular standen, als das Formular geöffnet wurde. Ich habe nun also berechnete Daten, auf Grundlage der Daten, die ich vorher und nicht auf Grundlage, die ich gerade eingegeben habe. Mein Ziel ist es ja, berechneten Daten aufgrundlage der gerade eben eingegeben Werte zu erhalten.

Zitat von: knobbi38 am Januar 11, 2025, 20:21:56
ZitatCode [Auswählen] Erweitern
Dim lngZutatSammlIDUfo1 As Integer
Ist das ein Typo? Wenn schon Präfixe verwendet werden, sollten sie mit der Deklaration auch übereinstimmen.
Was ist ein Typo? Danke für den Hinweis mit dem Präfix.
Dim IntZutatSammlIDUfo1 As Integer wäre wahrscheinlich besser gewesen.


Zitat von: knobbi38 am Januar 11, 2025, 20:21:56Btw.:
ZitatCode [Auswählen] Erweitern
ZEText = Forms("frmPopRezeptAlsZutat").Controls("cboZugabeEinheit").Text
Solche Zuweisungen sollten grundsätzlich vermieden werden, denn die Werte können per Openargs beim Öffnen des Popups übergeben werden. Mal abgesehen davon, daß die .Text Eigenschaft hier falsch verwendet wird. Bis auf wenige Ausnahmen wird in Access immer die .Value Eigenschaft verwendet.
Es geht darum, den Wert für eine MSG-Meldung weiter zu verwenden. Wenn ich die .Value-Eigenschaft verwende, ist der Wert bereits gespeichert. Bei der Text-Eigenschaft nicht. Ich will dem Nutzer ja vor der Speicherung die Meldung ausgeben, dass er gegebenenfalls etwas anderes eingeben soll.

KonradR

Hallo Christian,

Zitat von: Bitsqueezer am Januar 11, 2025, 22:03:08Text vs. Value hatten wir ja schon. Die Value-Eigenschaft ist normalerweise die Default-Eigenschaft, daher kann man sie auch einfach weglassen. In seltenen Fällen kann man schon mal etwas anderes bekommen als den Value, z.B. beim Zugriff auf die Fields eines Recordsets, je nach Art des Zugriffs erhältst Du dann das Feld selbst und nicht dessen Wert. Also wenn Du sichergehen möchtest, ist ".Value" zu schreiben, zumindest nicht falsch.
Danke ja, Value reicht hier vollkommen aus. Ich habe es nochmal im Überwachungsfenster geprüft.

Zitat von: Bitsqueezer am Januar 11, 2025, 22:03:08wenn ich Dir einen Tip zu Usability geben darf: Form_BeforeUpdate sollte der "Fehlersammler" sein. Nicht der Code, der den User zur Weißglut nervt:
    • Select Case kann immer nur ein True behandeln, beim ersten Case, das zutrifft, ist Ende (das ist nicht in allen Programmiersprachen so, aber in VBA)
    • wenn man mehr als einen Fehler testen will, dann ist es besser, einzelne Ifs zu schreiben (die dann alle durchgegangen werden), und dann je aufgetretenem Fehler eine String-Variable zu erweitern, in der die Fehler gesammelt werden. Dann kann man am Ende eine gesammelte Fehlermeldung ausgeben.
    • in Deiner aktuellen Version bekommt der User nur den ersten Fehler per Messagebox, er behebt ihn, versucht erneut zu speichern und bekommt den 2. Fehler usw., im schlimmsten Fall alle nacheinander. Das nervt gewaltig.
    [/list]
    Ich glaube, du bist jetzt der Dritte, der das hier im Forum anspricht. Ich werde es die Tage abändern. Das scheint wirklich ein wesentlicher Punkt zu sein.

    Zitat von: Bitsqueezer am Januar 11, 2025, 22:03:08Test auf leeres Feld: Ich empfehle Dir, statt "IsNull" besser Nz zu verwenden. Mit Nz kannst Du einen Austauschwert für NULL angeben, denn ein optisch leeres Feld muß nicht zwingend NULL sein, es kann auch ein Leerstring sein. Mit Nz ist "" immer der Standardaustauschwert, somit kannst Du testen "If Nz(Feld) = "" Then" und hast immer beide Varianten abgesichert. Der Rest ist von den Einstellungen des Feldes im Tabellendesign abhängig (ob Leereingaben zulässig sind).
    Sehr praktisch, vielen Dank. Da habe ich den Fall für einen Leerstring abgedeckt.

    Zitat von: Bitsqueezer am Januar 11, 2025, 22:03:08Integer: Sei vorsichtig mit der Verwendung von Integern. In anderen Programmiersprachen ist das ein 32Bit-Wert, in VBA ist es nur 16Bit. Das fällt bei Speicherung von ID-Werten erst mal nicht auf, bis Du über die +-Grenze von 32767 hinauskommst, was für IDs nicht allzuviel ist. Es gibt nahezu nie eine Einsatznotwendigkeit für Integer und in Zeiten von Gigabyte-RAM ist auch kein Speichersparen mehr notwendig. Daher am besten immer Long verwenden, dann bist Du im Allgemeinen immer auf der sicheren Seite (und ID-Felder von Tabellen können keine höheren Werte produzieren, außer im seltenen Fall, daß es ein Bigint ist, was in Access auch noch nicht so lange gibt).
    Ok, bei Integer ist das Ende eher erreicht. Hier ging es um eine Nachschlagetabelle für Rezepteinheiten. Da gibt es ja nicht so viele, dass ich über die Grenze von 32.767 herauskomme. Es sei denn, es soll eine Datenbank für alle Sprachen dieser Welt mit all deren Rezepteinheiten. Aber ja, Long ist sicherer. Dann werde ich das ändern.

    Zitat von: Bitsqueezer am Januar 11, 2025, 22:03:08da das nicht der gesamte Code ist, kann man nur ahnen, was da noch alles kommen mag. Bei so vielen "Dim"s wird man aber schon skeptisch. Wenn Du schon selbst gesehen hast, daß da welche gar nicht gebraucht werden, kommentiere die Zeile am besten aus, dann kannst Du sie später auch gleich ganz rausnehmen
    Absolut. Danke für den Tip. Ich finde, dass es manchmal Sinn macht eine Zeile noch auskommentiert im Code zu belassen. Wenn dann alles funktioniert, kann ich es löschen. Das schafft eine bessere Übersicht.
    Zitat von: Bitsqueezer am Januar 11, 2025, 22:03:08Zugriff auf Felder: Die maximal umständlichste und dazu noch vom Compiler nicht prüfbare Syntax mit Zugriff per Namen in Strings. Da "frmPopRezeptAlsZutat" vermutlich das Formular ist, in dem Du den Code stehen hast, kannst Du auch ganz einfach "Me.cboZugabeEinheit" schreiben. Und das kann der Compiler dann auch prüfen (ob es das Control auch gibt).

    Test auf leeres Feld: Ich empfehle Dir, statt "IsNull" besser Nz zu verwenden. Mit Nz kannst Du einen Austauschwert für NULL angeben, denn ein optisch leeres Feld muß nicht zwingend NULL sein, es kann auch ein Leerstring sein. Mit Nz ist "" immer der Standardaustauschwert, somit kannst Du testen "If Nz(Feld) = "" Then" und hast immer beide Varianten abgesichert. Der Rest ist von den Einstellungen des Feldes im Tabellendesign abhängig (ob Leereingaben zulässig sind). Das wurde hier im Forum schon des Öfteren angesprochen. Das habe ich bei aktuellem Code schon angepasst. Hier noch nicht. Allerdings ist der Vorteil von dieser Variant, dass Intellisens arbeiten kann. Gut, wenn ich den Formularnamen mit Form_ am Anfang reinschreibe, dann wirkt auch hier Intellisens und der Compiler kann es prüfen.
    Zitat von: Bitsqueezer am Januar 11, 2025, 22:03:08Zuweisung an eine String-Variable: Bitte beachte, daß außer "Variant" kein Variablentyp mit NULL umgehen kann.
    Danke. Das wusste ich noch nicht, aber hier brauche ich den Datentyp STRING tatsächlich.

    Zitat von: Bitsqueezer am Januar 11, 2025, 22:03:08Wieso ist die Fehlermeldung zu: "IsNull(Me.txtZugabeMenge.Value) And IsNull(Me.cboZugabeEinheit.Value)", daß es Leerzeichen in den Feldern gibt? NULL steht für "Nichts".
    Da ist meine Fehlermeldung tatsächlich falsch oder missverständlich. Das ändere ich noch ab. Danke für den Tip.

    Zitat von: Bitsqueezer am Januar 11, 2025, 22:03:08Auf "SELECT *" verzichten: Immer die genaue Feldliste angeben, die Du wirklich haben willst. Gründe dafür findest Du mit Google etc. leicht massenhaft. Zu oft aufgeschrieben, um es zum 1000.Mal zu wiederholen.
    Ich habe gerade mal nachgeschaut. Das führt zu einer besseren Leistung, weil nicht alle Daten abgerufen werden müssen. Das macht Sinn.

    Zitat von: Bitsqueezer am Januar 11, 2025, 22:03:08Möglichst auf zusammengesetzte SQL-Strings verzichten. Dazu mal unter "SQL Injection" suchen. Das trifft zwar im Fall von Access nicht zu, da man in Access keine SQL-Batches schreiben kann, aber besser gleich richtig angewöhnen.
    Das habe ich auch schon gehört. Aber wiedersprichst du dir da nicht im 1. Punkt? Da habe ich deinen Beitrag so verstanden, dass die Fehlermeldung in einen SQL-String übergeben werden soll. Wäre das dann nicht ein zusammengesetzter SQL-String bzw. wäre in diesem Fall, wenn es ein zusammengesetzter SQL-String ist, an dieser Stelle also sinnvoll?

    Zitat von: Bitsqueezer am Januar 11, 2025, 22:03:08Natürlich hat sicher jedes Modul, wie es jeder macht, "Option Explicit" als erste Zeile und Du nutzt ja auch sicher immer den Kompiler..... oder?
    Tatsächlich nutze ich den Compiler und in jedem Modul seht in der ersten Zeile "Option Explicit". Ich arbeite auch mit dem Überwachungsfenster. Sonst wüsste ich gar nicht, wie ich die Fehler alle finden soll.