Announcement

Collapse
No announcement yet.

Lookup-Feld in ADOQuery-Komponente -> "An unknown error has occured"

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Lookup-Feld in ADOQuery-Komponente -> "An unknown error has occured"

    Hallo!

    Ich habe eine ADOQuery-Komponente, mit 3 Feldern die ich mal mit Feld1-Feld3 benennen möchte.
    Feld1 und Feld2 sind normale Datenfelder, die aus einer Datenmenge kommen. Feld1 dient als Zuordnungsfeld zu einem Vaterdatensatz und wird daher beim hinzufügen eines neuen Datensatzes mit der VaterID vorbelegt. Feld2 wird von dem LookUp-Feld, Feld3, mit einem Integer-Wert gefüllt.
    Soweit funktioniert auch alles.
    Nun habe ich eine Button "Neu", bei dem ich einen Add-Befehl auf die ADOQuery-Komponente absetze. Gleich im nächsten Schritt, bevor noch eine User-Aktion folgen kann, belege ich das Feld1 mit der aktuellen Vater-ID vor. Und hier kracht es dann mit der Fehlermeldung "An unknown error has occured". Die Anwendung läuft dann aber trotzdem weiter.
    Was ich nun herausgefunden habe ist, dass wenn ich, bevor ich das Feld1 mit der Vater-ID belege, das Feld2, wo ja der LookUp-Ergebniswert reinkommt, mit irgendeinem Wert vorbelege, dass dann kein Fehler auftaucht.
    In diesem Fall ist da auch ein akzeptierbarer Workaround, nur wenn mehrere Lookup-Felder vorhanden sind, hilft der auch nicht mehr.

    Ich hoffe ich habs einigermaßen verständlich geschrieben. Ist halt auch etwas schwer in Worte zu fassen ;o)

    Hoffe jemand kann mit helfen!

    Danke,

    Markus

  • #2
    Hallo,

    verwendet die TADOQuery-Komponente eine feststehende SQL-Anweisung oder wird der SQL-Text zur Laufzeit ausgetauscht/verändert? Welche Datenbank steckt dahinter und nutzt das Programm clUseServer oder clUseClient?

    P.S: Der Einsatz von TADOQuery ist generell eine schlechte Wahl, TADODataSet bzw. TADOCommand ist besser

    Comment


    • #3
      Hallo,

      der SQL ist von anfang an der gleiche. Nur der Filter wird zur Laufzeit geändert.
      Hinter der ganzen Sache steht ein SQL-Server 2000.
      Auf meinem Rechner hab ihc Delphi5 mit den zahlreichen Update-Packs und MDAC 2.6
      Das Programm nutzt den Client-Cursor und die verschiedenen ADO-Komonenten sind in einem Daten-Modul gekapselt.

      Nun, was Sie mir da in Ihrem PS überbracht haben, ist für mich eine Hiobsbotschaft, da ich ausschliesslich die Query-Komponente verwende.
      Ich dachte gerade die wäre eine gute Lösung.

      Danke und Grüße,

      Marksu Jun

      Comment


      • #4
        Hallo,

        hinter TADOQuery steckt nur eine Kompatibilitäts-Komponente, die für den kurzzeitigen Gebrauch im Rahmen der Migration einer alten BDE-Anwendung auf ADO gedacht ist. TADOQuery versucht den Spagat zwischen BDE und ADO - und muss daher viele Kompromisse und Einschränkungen eingehen. Im Gegensatz dazu ist TADODataSet nur für ADO ausgelegt und übernimmt die Fähigkeiten von TADOTable + TADOQuery + TADOStoredProc, ohne Kompromisse eingehen zu müssen. Um es drastischer zu formulieren: TADOQuery ist für die Marketing-Leute gedacht, damit Borland auf die Verkaufspackung schreiben kann, dass ein "einfacher" Umstieg von der BDE auf ADO unterstützt wird. Ein "richtiges" Programm schreibt man dann aber mit TADODataSet. Leider fehlt dieser Hinweis auf der Verpackung :-)

        Wie sieht ein kurzes Beispielprojekt aus (am besten mit der MS SQL Server 2000-Beispieldatenbank Northwind), mit dem dieses Problem jederzeit reproduziert werden kann

        Comment


        • #5
          Hallo Herr Kosch!

          Nun, da habe ich ja wohl gerade aufs falsche Pferd gesetzt ;o).
          Vielen Dank für die Erklärung.

          Ein Beispielprojekt habe ich an die von Ihnen hinterlegte Adresse geschickt.

          Vielen Dank,

          Markus Jun

          Comment


          • #6
            Hallo Herr Kosch!

            Haben Sie mein Beispielprogramm bekommen??
            Konten Sie etwas erreichen??

            Ich habe auch nochmal das ganze mit ADODataSet probiert und da ist der selbe Fehler aufgetreten.

            Viele Grüße und Danke,

            Markus Jun

            Comment


            • #7
              Hallo,

              >Haben Sie mein Beispielprogramm bekommen??

              nein (oder ich habe sie als vermeintliche Werbe-eMail gleich ungelesen gelöscht). Damit das nicht ein 2. Mal passiert, sollte die Betreff-Zeile irgendwie auffällig sein (Bsp: FORUM, Entwickler-FORUM etc. mit angegeben)

              Comment


              • #8
                Hallo,

                ich habe mir das Beispielprojekt angeschaut. Über das <b>ftLookup</b>-Feld ist die Datenmenge der TADOQuery mit der Datenmenge der TADOTable verbunden:
                <pre>
                object ADOQuery1Categorie: TStringField
                DisplayWidth = 15
                FieldKind = fkLookup
                FieldName = 'Categorie'
                LookupDataSet = ADOTable1
                LookupKeyFields = 'CategoryID'
                LookupResultField = 'CategoryName'
                KeyFields = 'CategoryID'
                Size = 50
                Lookup = True
                end
                </pre>
                Es sind somit 3 Fälle denkbar.

                Fall A:
                <pre>
                procedure TForm1.Button1Click(Sender: TObject);
                begin
                ADOQuery1.Append;
                DBGrid1.Options := [dgEditing, dgTitles, dgIndicator, dgColumnResize,
                dgColLines, dgRowLines, dgTabs, dgCancelOnExit];
                end;
                </pre>
                Fall B:
                <pre>
                procedure TForm1.Button1Click(Sender: TObject);
                begin
                ADOQuery1.Append;
                ADOQuery1.FieldByName('UnitsInStock').AsInteger := 0;
                ADOQuery1.FieldByName('UnitsOnOrder').AsInteger := 0;
                DBGrid1.Options := [dgEditing, dgTitles, dgIndicator, dgColumnResize,
                dgColLines, dgRowLines, dgTabs, dgCancelOnExit];
                end;
                </pre>
                Fall C:
                <pre>
                procedure TForm1.Button3Click(Sender: TObject);
                begin
                ADOQuery1.Append;
                ADOQuery1.FieldByName('CategoryID').AsInteger := 0;
                ADOQuery1.FieldByName('UnitsInStock').AsInteger := 0;
                ADOQuery1.FieldByName('UnitsOnOrder').AsInteger := 0;
                DBGrid1.Options := [dgEditing, dgTitles, dgIndicator, dgColumnResize,
                dgColLines, dgRowLines, dgTabs, dgCancelOnExit];
                end;
                </pre>
                Ergebnis: <br>
                Fall A: Scheinbar OK (Problem erscheint erst dann, wenn nach der Eingabe die Spalte gewechselt wird) <br>
                Fall B: Fehler in der VCL <br>
                Fall C: OK (da der Fremdschlüsselwert zuerst gefüllt wird)

                Es ist wichtig, in der Ereignisbehandlungemethode für <b>OnNewRecord</b> alle die Felder zu initialisieren, die ausgefüllt werden müssen bzw. die als Lookup-Spalten verwendet werden. Nur dann kann die VCL die Verbindung zur anderen Datenmenge jederzeit richtig anzeigen.

                Wie ein Blick in das Log des Profilers des MS SQL Server zeigt, ist ADO nicht im Spielt (d.h. zu diesem Zeitpunkt werden keine Anweisungen zur Datenbank geschickt)

                Comment


                • #9
                  Hallo Herr Kosch!

                  Vielen Dank für Ihre Hilfe!

                  Die Initialisierung funktioniert bei nur einem Lookup-Feld wunderbar,
                  aber bei zwei Feldern kann sich die VCL nicht einig werden, welches zu erst initialisiert werden soll.
                  Bei mehr als einem Lookup-Feld hat man überhaupt keine Möglichkeit
                  mehr, mit einem Workarroud um das Problem herum zu kommen.

                  Lässt sich das überhaupt nicht umgehen??

                  Ich habe ja auch schon probiert, dass ich die Felder, die ich vorher, also beim Neu Anlegen-Button-Click, belege, erst vor dem Post der Daten belege, aber dann kommen sich auch die Lookup-Felder in die Quere und zwar dann, wenn ich aus dem einen Lookup-Feld einen Datensatz auswähle und in dem Anderen noch keiner ausgewählt ist.

                  Wäre wirklich toll wenn Sie mir helfen könnten.

                  Vielen Dank und viele Grüße,

                  Markus Jun

                  Comment


                  • #10
                    Hallo,

                    in jedem Fall können wir die von Delphi fälschlicherweise ausgelöste EOleException ignorieren, wie das folgende Beispiel zeigt. Ich habe dort gleich 2 ftLookup-Felder eingerichtet:
                    <pre>
                    unit Unit1;

                    interface

                    uses
                    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
                    ADODB, Grids, DBGrids, StdCtrls, Db;

                    type
                    TForm1 = class(TForm)
                    ADOConnection1: TADOConnection;
                    Button1: TButton;
                    Button2: TButton;
                    DBGrid1: TDBGrid;
                    DataSource1: TDataSource;
                    ADODataSetProducts: TADODataSet;
                    ADODataSetCategories: TADODataSet;
                    ADODataSetCategoriesCategoryID: TAutoIncField;
                    ADODataSetCategoriesCategoryName: TWideStringField;
                    ADODataSetProductsProductID: TAutoIncField;
                    ADODataSetProductsProductName: TWideStringField;
                    ADODataSetProductsSupplierID: TIntegerField;
                    ADODataSetProductsQuantityPerUnit: TWideStringField;
                    ADODataSetProductsUnitPrice: TBCDField;
                    ADODataSetProductsUnitsInStock: TSmallintField;
                    ADODataSetProductsUnitsOnOrder: TSmallintField;
                    ADODataSetProductsReorderLevel: TSmallintField;
                    ADODataSetProductsDiscontinued: TBooleanField;
                    ADODataSetProductsKategorie: TStringField;
                    ADODataSetProductsCategoryID: TIntegerField;
                    ADODataSetSupplier: TADODataSet;
                    ADODataSetSupplierSupplierID: TAutoIncField;
                    ADODataSetSupplierCompanyName: TWideStringField;
                    ADODataSetProductsFirma: TStringField;
                    procedure Button1Click(Sender: TObject);
                    procedure Button2Click(Sender: TObject);
                    procedure ADODataSetProductsNewRecord(DataSet: TDataSet);
                    private
                    { Private-Deklarationen }
                    public
                    { Public-Deklarationen }
                    end;

                    var
                    Form1: TForm1;

                    implementation

                    {$R *.DFM}

                    uses ComObj;

                    procedure TForm1.Button1Click(Sender: TObject);
                    begin
                    ADODataSetProducts.Append;
                    DBGrid1.Options := [dgEditing, dgTitles, dgIndicator, dgColumnResize,
                    dgColLines, dgRowLines, dgTabs, dgCancelOnExit];
                    end;

                    procedure TForm1.Button2Click(Sender: TObject);
                    begin
                    ADODataSetProducts.Cancel;
                    end;

                    procedure TForm1.ADODataSetProductsNewRecord(DataSet: TDataSet);
                    begin
                    try
                    ADODataSetProductsCategoryID.Value := 0;
                    ADODataSetProductsSupplierID.Value := 0;
                    ADODataSetProductsUnitsInStock.Value := 0;
                    ADODataSetProductsUnitsOnOrder.Value := 0;
                    except
                    on E: EOleException do
                    ; // wir wissen es besser !
                    else
                    Raise;
                    end;
                    end;

                    end.
                    </pre>
                    Zur Laufzeit (EXE wird nicht in Delphi gestartet) ist von der Exception nichts mehr zu sehen, so dass der Anwender den Datensatz ausfüllen und speichern kann

                    Comment


                    • #11
                      Hallo Herr Kosch!

                      Ja, das ist mir neulich auch durch Zufall, als ich das Programm ohne dass ich die Delphi-IDE laufen hatte, aufgefallen, dass von dem Fehler nix mehr zu sehen ist. Ich hatte nur wegen eventuellen Auswirkungen Bedenken.
                      Aber wenn Sie sagen, dass dieser Bug ignoriert werden kann, werd ich das einfach tun.

                      Vielen Dank an dieser Stelle, dass Sie sich dem Thema angenommen und mir sehr geholfen haben.

                      Vielen Dank und ein schönes WE,

                      Markus Jun

                      Comment

                      Working...
                      X