Announcement

Collapse
No announcement yet.

Wie kann ich Autowert während Append

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

  • Wie kann ich Autowert während Append

    In einer Access-Datenbank habe ich zwei Tabellen, die miteinander in Verbindung stehen. In der einen Tabelle trage ich einen neuen Datensatz ein, deren Nummer (Autowert) in der anderen Tabelle gespeichert werden soll - wie geht das?

    Mein Versuch

    Tabelle2.Append;
    Tabelle1.FieldValues['NR'] := Tabelle2.FieldValues['NR']

    schlug leider fehl, weil nach Append offensichtlich kein Autowert (im Feld 'NR') ausgelesen werden kann. Was mache ich falsch?

  • #2
    Hallo,

    das folgende Beispiel zeigt, wie die Detail-Tabelle die AutoInc-Werte der Master-Tabelle einer ACCESS2000-Datenbank nutzt. Wesentlich für den Erfolg ist die Konfiguration im Objektinspektor:

    Beide Tabellen verwenden einen AutoWert-Primärschlüssel. Die beiden Tabellen dürfen jedoch nicht den gleichen Spaltennamen für die Fremdschlüsselspalte (Master-/Detail-Beziehung) verwenden. Während die Master-Tabelle die Spalte "ID" verwendet, benennt die Detail-Tabelle die Primärschlüsselspalte mit "DetailID" und die Fremdschlüsselspalte mit "MasterID".
    <pre>
    object ADOConnection1: TADOConnection
    ConnectionString =
    'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\TEMP\Out\AccessA' +
    'utoWert\AccessAutoWert.mdb;Persist Security Info=False'
    CursorLocation = clUseServer
    LoginPrompt = False
    Mode = cmShareDenyNone
    Provider = 'Microsoft.Jet.OLEDB.4.0'
    Left = 8
    Top = 8
    end
    object ADODataSetMaster: TADODataSet
    Connection = ADOConnection1
    CursorLocation = clUseServer
    CommandText = 'TblMaster'
    CommandType = cmdTableDirect
    Parameters = <>
    Left = 48
    Top = 8
    object ADODataSetMasterID: TAutoIncField
    FieldName = 'ID'
    end
    object ADODataSetMasterEintrag: TWideStringField
    FieldName = 'Eintrag'
    end
    end
    object DataSourceMaster: TDataSource
    DataSet = ADODataSetMaster
    Left = 80
    Top = 8
    end
    object ADODataSetDetail: TADODataSet
    Connection = ADOConnection1
    CursorLocation = clUseServer
    OnNewRecord = ADODataSetDetailNewRecord
    CommandText = 'select * from TblDetail where MasterID = :ID'
    DataSource = DataSourceMaster
    MasterFields = 'ID'
    Parameters = <
    item
    Name = 'ID'
    Attributes = [paNullable]
    DataType = ftInteger
    NumericScale = 255
    Precision = 255
    Value = 1
    end>
    Left = 48
    Top = 184
    object ADODataSetDetailDetailID: TAutoIncField
    FieldName = 'DetailID'
    end
    object ADODataSetDetailMasterID: TIntegerField
    FieldName = 'MasterID'
    end
    object ADODataSetDetailDetailWert: TWideStringField
    FieldName = 'DetailWert'
    end
    end
    object DataSourceDetail: TDataSource
    DataSet = ADODataSetDetail
    Left = 80
    Top = 184
    end
    </pre>
    Immer dann, wenn ein neuer Detail-Datensatz angelegt wird, belegt das Programm den Wert des dazupassenden Master-Datensatzes vor:
    <pre>
    procedure TForm1.ADODataSetDetailNewRecord(DataSet: TDataSet);
    begin
    ADODataSetDetailMasterID.Value := ADODataSetMasterID.Value;
    end;
    </pre&gt

    Comment


    • #3
      Vielen Dank für die ausführliche Antwort, die muss ich natürlich erst einmal auf mich einwirken lassen und testen - ich dachte eigentlich, dass es hierfür eine einfachere Lösung geben müsste.

      Denn sobald ich in Access einen neuen Datensatz beginne, in dem es ein Autowert-Feld gibt, dann trägt Access als erstes die neue Nummer in dieses Feld ein, sobald ich in irgendeinem anderen Feld einen der Einträge ändere. Das kann man in Delphi anscheinend nicht auslesen, oder

      Comment


      • #4
        Vielleicht sollte man die Frage auch noch mal etwas anders formulieren:

        Ich nehme zwei Tabellen in einer Access-Datenbank, in der zweiten Tabelle gibt es ein AutoWert-Feld, um eine bestimmte Nummer zu vergeben, auf die von mehreren Feldwerten in der ersten Datenbank zugegriffen wird. Wenn ich nun einen neuen Datensatz in die zweite Tabelle schreibe, dann muss es doch möglich sein, den Wert zu erfahren, der meinem Autowert-Feld zugewiesen wird. - Oder habe ich in der ersten Antwort etwas übersehen?

        Wie gesagt, es handelt sich nicht um zwei Tabellen, die über jeweils ein Autowert-Feld verknüpft sind

        Comment


        • #5
          Hallo Wolfgang,

          ich hab mir Deine Frage gerade mal durchgelesen und hoffe das ich es richtig verstanden habe.

          Die ID (Access/Autoinc.) des neu angelegten Datensatzes kann man so abfragen:

          <P>
          <PRE>
          {*******************************************}
          DataModule1.SelectNewID.active := true;
          NeueID := DataModule1.SelectNewID.Fields[0].value;
          DataModule1.SelectNewID.active := false;
          {*******************************************}

          Die SQL Syntax in der Query (bei mir TADODataSet) sieht so aus:

          SELECT @@Identity

          <P>
          </PRE>

          Damit wird die zuletzt über die Connection übertragene ID ermittelt.
          Dazu muß das Feld persistent aufgenommen werden. Der Wert AutoGenerateValue (TADODataSet im Objektinspektor) des Felds muß auf arAutoInc gesetzt werden.
          <P>

          Das läuft dann so. Wenn ein Master oder auch Detaildatensatz angelegt wird (alle verfügen über ein Feld ID / Autoinc), starte ich einmal diese Abfrage und bekomme die ID des zuletzt angelegten Datensatzes.

          Viele Grüße
          <P>
          Walte

          Comment


          • #6
            Vielen Dank, das werde ich einmal ausprobieren

            Comment


            • #7
              Hallo,

              &gt;..dass es hierfür eine einfachere Lösung geben müsste...

              mein Beispiel kommt mit einer einzigen Zeile aus, wie soll das noch einfacher gehen?

              Wenn TADOConnection und TADODataSet im Objektinspektor <b>richtig</b> konfiguriert wurde, ermittelt ADO den AutoInc-Wert <b>automatisch</b> ohne jedes eigenes Zutun. Wir können ihn direkt im Programm sofort auslesen. Der "Umweg" über eine nachträgliche SELECT-Abfrage ist nicht notwendig

              Comment


              • #8
                Hallo Herr Kosch,

                ich wollte Sie auf keinen Fall kritisieren. ich hoffe Sie mißverstehn mich nicht. Ich bin Ihnen für Ihren Einsatz und Ihre Hilfe hier sehr dankbar.

                Zum Problem: Mit dem Ereignis OnNewRecord kann man ja nur arbeiten wenn man das Ereignis auch zur Verfügung hat. Also einen Komponente (TADODataSet o.ä.). Bei mir wird der neue Datensatz nicht erst in eine Komponente geschrieben und später mit Update, .... in die DB geschickt. Ich habe ledigliche einen View mit den nötigsten Daten. Beim neu anlegen öffne ich ein Fenster mit Edits und trage die Werte ein. Anschließend schreibe ich den neuen Datensatz (mit nativem Command Objekt) direkt in die DB und aktualisiere den View. Da ich eventuell noch die vergebene ID benötige verwende ich die Lösung mit @@Identity bevor ivh die View aktualisiere. Die Idee hab ich übrigens aus Ihrem Buch "ADO und Delphi". Sind also Ihre Lorbeeren.

                Viele Grüße und vielen Dank
                Walte

                Comment


                • #9
                  Ich will mich ja hier nicht in einen Expertenstreit einmischen, aber nach langem Rumprobieren bin ich zu folgender Lösung gekommen.

                  Table2.Append;
                  //Feldwerte füllen mit Ausnahme des Autoinc-Feldes
                  Table12Post;

                  nun kann man mit
                  integer i := Table2.FieldValues['NR'] den Wert des Autoinc-Feldes auslesen und über

                  Table1.FieldValues['xy'] := i

                  übernehmen.

                  Scheint zu funktionieren - oder habe ich hier etwas übersehen

                  Comment


                  • #10
                    Hallo Wolfgang,

                    so wie Du es jetzt machst ist es schon richtig. So kann der ID Wert gelsen und und in einer anderen Tabelle geschrieben werden. Das kann man sich aber auch noch sparen indem man die Vorgehendweise von Herrn Kosch verwendet. Der ID Wert wird dann automatisch ausgelesen und mit

                    <PRE>
                    procedure TForm1.ADODataSetDetailNewRecord(DataSet: TDataSet);
                    begin
                    ADODataSetDetailMasterID.Value := ADODataSetMasterID.Value;
                    end;
                    </PRE>

                    automatisch in die andere Tabelle geschrieben. Also wirklich nur eine einzige Zeile.
                    Mein Beispiel hat da eigentlich nix mit zu tun und wäre nur für den Fall geeignet falls das ganze im Netzwerk abläuft und dann anstatt mit Tables, mit Query Komponenten.

                    Schau Dir das Beispiel von Herrn Kosch nochmal genau an und konfiguriere Deine Tabellen im Objektinspektor so wie er es im Beispiele gemacht hat und dann noch die eine Zeile im OnNewRecord Ereignis und Du wirst sehn das es nicht einfacher geht.

                    Viele Grüße<P>
                    Walte

                    Comment


                    • #11
                      Gut, danke für den Tip(p) - werde ich auch noch mal ausprobieren

                      Comment


                      • #12
                        Hallo Walter Sobchak,

                        funktioniert das auch im Netzwerk ?
                        Was passiert, wenn mehrere Anwender sehr zeitnah einen
                        Master-Datensatz erzeugen. Könnte deine Funktion evtl.
                        die zuletzt generierte ID eines anderen Anwenders liefern ?

                        Viele Grüße
                        domino

                        P.S.:
                        Bowling ist cool..

                        Comment


                        • #13
                          Hallo,

                          gerade für's Netzwerk ist das ja gedacht. Es wird die letzte ID zurückgegeben die über die Connection angelegt wurde. Im Netzwerk hat ja jeder seine eigene Connection (Instanz des Programms) auf dem Rechner. Bisher hat es immer funktioniert auch wenn Datensätze in sehr kurzen Zeitabständen von verschiedenen Clients angelegt wurden.
                          Diese Methode eigent sich prima z.B. zum fokusieren des neuen Datensatzes in einem DBGrid.

                          Viele Grüße<P>
                          Walte

                          Comment

                          Working...
                          X