Announcement

Collapse
No announcement yet.

Keine Rückmeldung bei Fehler aus der MSSQL

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

  • Keine Rückmeldung bei Fehler aus der MSSQL

    Hallo
    ich bekomme keine Fehlermeldung wenn in der DB ein Datensatz direkt gelöscht oder geändert wurde und ich ein Update über mein Programm machen

    so sieht meine SP aus
    CREATE PROCEDURE inserad_objekte_update
    @NAME nvarchar(50),
    @BESCHREIBUNG text,
    @ERSCHEINUNG text,
    @AUFLAGE int,
    @EINZELPREIS money,
    @VERBREITUNGSGEBIET text,
    @HEFTFORMAT_BREITE int,
    @HEFTFORMAT_HOEHE int,
    @SATZSPIEGEL_BREITE int,
    @SATZSPIEGEL_HOEHE int,
    @VERTRIEB text,
    @GELOESCHT bit,
    @USER_NAME nvarchar(50),
    @USER_TXT text,
    @USER_DATE datetime,
    @ID int
    AS
    SET NOCOUNT ON

    BEGIN TRANSACTION

    UPDATE [inserad_objekte]
    SET
    [NAME] = @NAME,
    [BESCHREIBUNG] = @BESCHREIBUNG,
    [ERSCHEINUNG] = @ERSCHEINUNG,
    [AUFLAGE] = @AUFLAGE,
    [EINZELPREIS] = @EINZELPREIS,
    [VERBREITUNGSGEBIET] = @VERBREITUNGSGEBIET,
    [HEFTFORMAT_HOEHE] = @HEFTFORMAT_BREITE,
    [HEFTFORMAT_BREITE] = @HEFTFORMAT_HOEHE,
    [SATZSPIEGEL_HOEHE] = @SATZSPIEGEL_BREITE,
    [SATZSPIEGEL_BREITE] = @SATZSPIEGEL_HOEHE,
    [VERTRIEB] = @VERTRIEB,
    [GELOESCHT] = @GELOESCHT,
    [USER_NAME] = @USER_NAME,
    [USER_TXT] = @USER_TXT,
    [USER_DATE] = @USER_DATE

    WHERE
    [ID] = @ID

    IF ( @@ERROR = 0)
    COMMIT TRANSACTION
    ELSE
    ROLLBACK TRANSACTION
    GO

    und so meine Updatecommand

    /************************************************** ****************************
    //Constructor
    constructor TObjekte.Create;
    begin
    inherited Create;
    // TODO: Hier die Konstruktorlogik einfügen

    //Adapter erzeugen und Konfigurieren
    FAdapter := OleDbDataAdapter.Create('SELECT * FROM inserad_objekte WHERE GELOESCHT = 0' , gDatabaseInserad.Connection);
    FAdapter.ContinueUpdateOnError := True;
    FAdapter.UpdateCommand := FUpdateCommand;
    FAdapter.InsertCommand := FInsertCommand;
    FAdapter.DeleteCommand := FDeleteCommand;

    //Wenn DataTable im DataSet schon vorhanden dann löschen
    if gDataSetInserad.Tables.CanRemove(gDataSetInserad.T ables['inserad_objekte']) then
    begin
    gDataSetInserad.Tables['inserad_objekte'].Clear;
    end;

    //Ins gDataSetInserad füllen
    gDatabaseInserad.Open;
    FAdapter.FillSchema(gDataSetInserad, SchemaType.Mapped, 'inserad_objekte');
    FAdapter.Fill(gDataSetInserad, 'inserad_objekte');
    gDatabaseInserad.Close;
    end;

    //################################################## ############################
    //################################################## ############################
    // Commands
    //################################################## ############################
    //################################################## ############################

    //************************************************** ****************************
    //Update Command
    function TObjekte.FUpdateCommand() : OleDbCommand;
    var
    FUpdPar : OleDbParameter;
    begin
    //Update Command
    Result := OleDbCommand.Create;
    Result.CommandType := CommandType.StoredProcedure;
    Result.CommandText := 'inserad_objekte_update';
    Result.Connection := gDatabaseInserad.Connection;

    //Update CommadParameter
    Result.Parameters.Clear;
    Result.Parameters.Add('@NAME', OleDbType.VarWChar, 50, 'NAME');
    Result.Parameters.Add('@BESCHREIBUNG', OleDbType.LongVarChar, 16, 'BESCHREIBUNG');
    Result.Parameters.Add('@ERSCHEINUNG', OleDbType.LongVarChar, 16, 'ERSCHEINUNG');
    Result.Parameters.Add('@AUFLAGE', OleDbType.Integer, 4, 'AUFLAGE');
    Result.Parameters.Add('@EINZELPREIS', OleDbType.Decimal, 9, 'EINZELPREIS');
    Result.Parameters.Add('@VERBREITUNGSGEBIET', OleDbType.LongVarChar, 16, 'VERBREITUNGSGEBIET');
    Result.Parameters.Add('@HEFTFORMAT_HOEHE', OleDbType.Integer, 4, 'HEFTFORMAT_HOEHE');
    Result.Parameters.Add('@HEFTFORMAT_BREITE', OleDbType.Integer, 4, 'HEFTFORMAT_BREITE');
    Result.Parameters.Add('@SATZSPIEGEL_HOEHE', OleDbType.Integer, 4, 'SATZSPIEGEL_HOEHE');
    Result.Parameters.Add('@SATZSPIEGEL_BREITE', OleDbType.Integer, 4, 'SATZSPIEGEL_BREITE');
    Result.Parameters.Add('@VERTRIEB', OleDbType.LongVarChar, 16, 'VERTRIEB');
    Result.Parameters.Add('@GELOESCHT', OleDbType.Boolean, 1, 'GELOESCHT');
    Result.Parameters.Add('@USER_NAME', OleDbType.VarWChar, 50, 'USER_NAME');
    Result.Parameters.Add('@USER_TXT', OleDbType.LongVarChar, 16, 'USER_TXT');
    Result.Parameters.Add('@USER_DATE', OleDbType.DBTimeStamp, 8, 'USER_DATE');

    //Update Parameter
    FUpdPar := Result.Parameters.Add('@ID', OleDbType.Integer);
    FUpdPar.SourceColumn := 'ID';
    FUpdPar.SourceVersion := DataRowVersion.Original;
    end;


    kann mir jeamnd sagen was ich falsch mache?

    Raimund

  • #2
    Hallo,
    die gespeicherte Prozedure kann als Rückgabewert über <b>RETURN @@ROWCOUNT</b> die Anzahl der betroffenen Datensätze zurückliefern. Der Rückgabewert einer Stored Procedure wird in der <i>Parameters</i>-Kollektion in der Position <b>0</b> unter dem Parameternamen <i>@RETURN_VALUE</i> zurückgeliefert, so dass der Client nach dem Ausführen die Rückgabewert auslesen kann. Der UPDATE-Aufruf war dann erfolgreich, wenn der Wert 1 vorgefunden wird.
    Über <i>@@ERROR</i> wird nur der jeweils bei der letzten T-SQL-Anweisung aufgetretene Fehler gemeldet - aber ein UPDATE-Aufruf, bei dem die WHERE-Einschränkung keinen Treffer findet, ist kein Fehler.

    Der Microsoft SQL Server verwendet in der Voreinstellung den so genannten <b>Autocommit-Modus</b>, bei jedem jede fehlerfrei ausgeführte SQL-Anweisung automatisch über COMMIT bestätigt wird, während jede fehlerhaft ausgeführte SQL-Anweisung automatisch mit einem ROLLBACK quittiert wird. Wenn die Stored Procedure immer nur einen Aufruf für eine Tabelle ausführt, muss keine explizite Transaktion gestartet werden

    Comment


    • #3
      Hallo
      Leider nur die hälfte verstanden :-(
      woran erkenne ich das ein Datensatz schon bearbeitet, eingefügt oder gelöscht wurde
      den Autocommit Modus kann ich auch nicht finden
      ich dachte es wird mir jeder Fehler im DataGrid angezeigt (rotes Ausrufezeichen)

      Oder muss ich es im meinen SP's einarbeiten
      und wie fang ich es dann im Programm ab

      Comment


      • #4
        Hallo!

        Herr Kosch. Sie schreiben, das in der Parameters-Kollektion in Pos 0 der @RETURN_VALUE enthalten ist.
        Ich habe @@IDENTITY zurückgeben. In Parameter 0 ist jedoch der übergebene erste Parameter enthalten.

        Wie muß die Übernahme aussehen?

        mfg
        Thoma

        Comment


        • #5
          Hallo,
          &gt;..es wird mir jeder Fehler im DataGrid angezeigt (rotes Ausrufezeichen)

          das ist auch der Fall. Das Problem ist nur, dass für SQL eine UPDATE-Anweisung, die "ins Leere" greift, <b>kein</b> Fehler ist. Es ist die Aufgabe des Clients, zu prüfen, wie viele Datensätze betroffen waren. Der <b>Data Adapter Configuration Wizard</b> von Visual Studio geht zum Beispiel so vor: Er generiert eine Stapelanweisung, die a) zurerst UPDATE aufruft und b) danach den Datensatz über SELECT neu einliest. Sobald nach dem Aufruf kein Datensatz ankommt (weil ein anderer Benutzer diesen in einer anderen Transaktion in der Zwischenzeit gelöscht hat), löst ADO.NET automatisch einen Fehler aus (weil die SELECT-Abfrage nicht geliefert hat).

          Wenn der UPDATE-Aufruf in eine Stored Procedure ausgelagert wird, kann das gleiche Verhalten über den folgenden Weg erreicht werden:

          <pre>
          CREATE PROCEDURE xyz (@paramliste..., @PK INT)
          AS
          SET NOCOUNT ON;
          UPDATE tabelle
          SET feld = Wert
          WHERE pk = @PK;
          RETURN @@ROWCOUNT
          GO
          </pre>

          Nach dem Aufruf kann der Client den Rückgabewert der Stored Procedure auslesen: <br>
          a) Wert 1: Die UPDATE-Anweisung hat einen Datensatz geändert. <br>
          b) Wert 0: Die UPDATE-Anweisung keinen keinen Datensatz geändert, weil die WHERE-Einschränkung zu keinem Treffer geführt hat.
          <br>
          &gt;..den Autocommit Modus kann ich auch nicht finden ...
          Dieser ist beim MS SQL Server automatisch aktiv und wird erst dann verlassen, wenn die Datenbankverbindung über BEGIN TRANS (oder eine der anderen SET-Funktionen) eine eigene (explizite) Transaktion startet.
          Der Vollständigkeit halber muss erwähnt werden, dass der MS SQL Server gleich 3 Transaktions-Betriebsarten unterstützt:<br>
          1. Autocommit-Transaktionsmodus
          2. Impliziter Transaktionsmodus (SET IMPLICIT_*TRANSACTIONS ON)
          3. Expliziter Transaktionsmodus
          &#10

          Comment


          • #6
            Hallo
            es wird helle :-)

            meine SP habe ich um das erweitet
            SELECT @iRow = @@ROWCOUNT, @iError = @@ERROR

            IF ( @iError = 0)
            COMMIT TRANSACTION
            ELSE
            ROLLBACK TRANSACTION

            RETURN @iRow
            RETURN @iError
            go

            nur habe ich jetzt das Problem wie frage ich das RETURN ab?
            bei Result.Parameters.Add('@iRow', OleDbType.Integer, 4);

            bekomme ich das kleine rote Ausrufezeichen im DataGrid mit dem Fehler zuviel Argumente

            ich weiß leider nicht wie ich ein Return Werte aus dem SQL Server in mein Delphiprogramm auswerte bzw ausles

            Comment


            • #7
              Hallo,
              beim Zugriff über <i>SqlCommand</i> muss der Rückgabewert <b>@RETURN_VALUE</b> der 1. Paramter in der Parameters-Kollektion sein:

              aCmd.Parameters.Add("@RETURN_VALUE",
              SqlDbType.Int).Direction = ParameterDirection.ReturnValue;

              Nach dem Ausführen der Stored Procedure wird der Rückgabewert <b>@RETURN_VALUE</b> über die Kollektion ausgelesen:

              <pre>
              aCmd.ExecuteNonQuery();
              iMsgCount = (int) aCmd.Parameters["@RETURN_VALUE"].Value;
              </pre&gt

              Comment


              • #8
                Hallo
                "beim Zugriff über SqlCommand muss der Rückgabewert @RETURN_VALUE der 1. Paramter in der Parameters-Kollektion sein: "

                da war mein Fehler

                aber ich kann nur ein Return wert auswerten
                warum ?

                ich führe auch nicht aCmd.ExecuteNonQuery();
                aus

                das Command
                //Update Command
                Result := OleDbCommand.Create;
                Result.CommandType := CommandType.StoredProcedure;
                Result.CommandText := 'inserad_objekte_update';
                Result.Connection := gDatabaseInserad.Connection;

                //Update CommadParameter
                Result.Parameters.Clear;
                Result.Parameters.Add('@RETURN_ERROR', OleDbType.Integer, 4).Direction := ParameterDirection.ReturnValue;
                Result.Parameters.Add('@NAME', OleDbType.VarWChar, 50, 'NAME');
                Result.Parameters.Add('@BESCHREIBUNG', OleDbType.LongVarChar, 16, 'BESCHREIBUNG');
                Result.Parameters.Add('@ERSCHEINUNG', OleDbType.LongVarChar, 16, 'ERSCHEINUNG');

                und dann die auswertung

                //Daten speichern
                gDatabaseInserad.Open;
                FAdapter.Update(gDataSetInserad, 'inserad_objekte');
                gDatabaseInserad.Close;

                //Fehler übergeben
                return_i := Convert.ToInt32(FAdapter.UpdateCommand.Parameters['@RETURN_ERROR'].Value);

                //Fehlerauswertung
                if (return_i <= 0) then
                begin
                //Fehlertext
                DialogBox('Der Datensatz konnte nicht gespeichert werden!!!' + #13#10 +
                'Der Datensatz ist entweder nicht mehr vorhanden' + #13#10 +
                'oder' + #13#10 +
                'der Datensatz wurde in der Zwischenzeit verändert.' + #13#10 +
                'Die Tabelle wird aktualisiert.' + #13#10 +
                'Bitte versuchen Sie es nochmal.'
                , DialogBoxLayout.STOP_OK);

                //Tabelle refreshen
                Refresh;
                end;

                Raimun

                Comment

                Working...
                X