0

Duplizieren von Datensätzen mit Untertabelle

Hallo, ich habe eine Tabelle namens 'Dokumente', in der ich Angebote, Aufträge und Rechnungen speichere. Die dazugehörigen Positionen sind in einer gleichnamigen Untertabelle gespeichert. Die Idee ist, aus einem Datenbestand verschiedene Dokumente generieren zu können, wobei natürlich auch die 'Positionen' erhalten bleiben sollen.

Dazu gibt es einen Button, über den ich per "create" den aktuellen Datensatz der Tabelle 'Dokumente' dupliziere, also mit den aktuellen Daten einen neuen Datensatz anlege und dann mit "openRecord" direkt dorthin springe. Das funktioniert soweit ganz gut, aber wie kriege ich es hin, dass auch die zugehörigen Daten der verbundenen Untertabelle 'Positionen' mit übertragen werden?

Beim Duplizieren des Datensatzes über die Ninox-Menüleiste geht es, da werden die Einträge der Untertabelle automatisch mit übernommen. Aber ein funktionsgleiches "duplicate" oder so als Befehl gibt es ja wohl nicht, oder? Wie bekommt man das manuell hin?

Hat jemand sowas schon mal gemacht oder zumindest eine Idee, wie es gehen könnte?

10 Antworten

null
    • Ninox Premiumpartner
    • Bastian_Vorholt
    • vor 6 Jahren
    • Gemeldet - anzeigen
    Ich habe soetwas schon öfters gebaut. Wichtig ist das du die id die in ninox in jeder Tabelle erstellt wird in einer Variable mit übergibst. Beispiel ein Angebot in eine Rechnung umwandeln:
    let n := Nr;
    let r := (create Rechnung);
    (let rn := r.Nr;
    for p in (select Angebotsposition where Angebot.Nr = n) do
    let PR := p.Artikel;
    let anz := p.Anzahl;
    let pr := p.Einzelpreis;
    let y := (create Rechnungsposition);
    y.(Rechnung := rn);
    y.(Artikel := PR);
    y.(Einzelpreis := pr);
    y.(Anzahl := anz)
    end
    )
    Kann dir später mal ein
    • Ninox Premiumpartner
    • Bastian_Vorholt
    • vor 6 Jahren
    • Gemeldet - anzeigen
    Kann dir später mal ein Beispiel schicken.
    • AxelE
    • vor 6 Jahren
    • Gemeldet - anzeigen
    Ah, super, danke! Und so schnell ... :)

    Ich werde mir das gleich in Ruhe ansehen und versuchen, das auf meine Situation zu übertragen. Melde mich dann wieder (so oder so).
    • Leonid_Semik
    • vor 6 Jahren
    • Gemeldet - anzeigen
    Seit dem letzten Update gibt es auch ein Befehl:
    ---

    duplicate(this)

    ---

    damit wir der aktuellen Datensatz mit Untertabellen dupliziert.
    • AxelE
    • vor 6 Jahren
    • Gemeldet - anzeigen
    Autsch! ;)

    Echt? Gibt's nun doch ein 'duplicate'? Okay, danke für die Info, als Freund des Einfachen werde ich das nachher mal probieren.

    Ich will euch auch nicht zu sehr beanspruchen, aber ich hatte nun im Schweiße meines Angesichts schon versucht, das Beispiel von magicnetworks für mich umzusetzen. Leider vergeblich. Ich bekomme keine Fehlermeldung, aber es werden auch keine Datensätze der Untertabelle übernommen. Und das 'openRecord' funktioniert jetzt auch nicht mehr (vorher schon). Wahrscheinlich habe ich (wieder mal) irgendwo einen logischen Fehler. Falls ihr noch Lust und Zeit habt, mal drüberzuschauen:

    let DokNr := Nr;
    let tKunde := Kunde;
    let tProjekt := Projekt;
    let tDokumenttyp := Dokumenttyp;
    let tDokumenttitel := Dokumenttitel;
    [...]
    let neuDok := (create 'B Dokumente');
    neuDok.(Kunde := tKunde);
    neuDok.(Projekt := tProjekt);
    neuDok.(Dokumenttyp := tDokumenttyp);
    neuDok.(Dokumenttitel := tDokumenttitel);
    [...]
    for Pos in select Positionen where Dokumente.Nr = DokNr do
    let tLeistung := Pos.Leistung;
    let tBeschreibung := Pos.Beschreibung;
    let tMenge := Pos.Menge;
    let tEinheit := Pos.Einheit;
    let tSatz := Pos.Satz;
    let neuPos := (create Positionen);
    neuPos.(Leistung := tLeistung);
    neuPos.(Beschreibung := tBeschreibung);
    neuPos.(Menge := tMenge);
    neuPos.(Einheit := tEinheit);
    neuPos.(Satz := tSatz)
    end;
    openRecord(record('B Dokumente',neuDok.Nr));
    alert("Neues Dokument erzeugt")
    • Leonid_Semik
    • vor 6 Jahren
    • Gemeldet - anzeigen
    Da fehlt noch bei neuDoc

    ---
    let neuNr:=neuDoc.Nr;
    ---

    Dann bei neuPos
    ---
    neuPos.Dokumente:=neuNr;
    ---

    und bei openRecord muss du die ID als Nummer deklarieren

    ---
    openRecord(record(‘B Dokumente’,number(neuDok.Nr)));
    ---
    • AxelE
    • vor 6 Jahren
    • Gemeldet - anzeigen
    So. Falls es jemanden interessiert, wie die Sache ausgegangen ist ...

    Leos Hinweise waren natürlich korrekt. Ohne die "Dokumente"-Verknüpfung konnte es ja nicht gehen. Allerdings funkionierte es auch nicht, nachdem ich den Code entsprechend ergänzt hatte. Vieles versucht, alles vergeblich. Keine Fehlermeldung, aber auch kein Kopieren der Daten der Untertabelle. Nix zu machen.

    Ich habe deshalb dann doch den Support bemüht. Auch für den war der Fehler nicht auf Anhieb erkennbar, aber am Ende stellte sich heraus, dass die Datensatz-IDs in numerische Werte umgewandelt werden müssen. Das hatte ich nach Leos Hinweis auf das "number" bei "openRecord" zwar auch schon mal probiert, allerdings nur halbherzig, und nicht konsequent auch in der ersten Zeile. Eine Datensatz-ID bzw. -Nummer war für mich halt per se numerisch. ;)

    Na ja, bei der Gelegenheit konnte immerhin noch eine weitere, grundsätzliche Frage geklärt werden: Warum heißt es mal "Id" und mal "Nr"? Lösung:

    "Id" = englischsprachige Ninox-Version
    "Nr" = deutschsprachige Ninox-Version
    "_id" = interne, technische Bezeichnung

    Letztere Schreibweise funktioniert also wohl immer, unabhängig von der jeweiligen Sprachversion des Nutzers, weshalb ich zukünftig nur noch diese Variante verwenden werde. An solchen Stellen scheint die Lokalisierung eher Fluch als Segen zu sein (zumal "ID/Id" als Kürzel ja auch im deutschen Sprachraum gängig ist). Der folgende Code würde in meinem Fall (Web, deutsch) also natürlich auch mit "Nr" statt "_id" funktionieren (jedoch nicht mit "Id", "id" oder "ID", und auch nicht mit "NR" oder "nr" ... ;):

    let DokNr := number(_id); <<--
    let tKunde := Kunde;
    let tProjekt := Projekt;
    let tDokumenttyp := Dokumenttyp;
    let tDokumenttitel := Dokumenttitel;
    [...]
    let neuDok := (create 'B Dokumente');
    neuDok.(Kunde := tKunde);
    neuDok.(Projekt := tProjekt);
    neuDok.(Dokumenttyp := tDokumenttyp);
    neuDok.(Dokumenttitel := tDokumenttitel);
    [...]
    let neuPosDok := neuDok._id;
    for Pos in select Positionen where number(DokumentNr._id) = DokNr do <<--
    let tLeistung := Pos.Leistung;
    let tBeschreibung := Pos.Beschreibung;
    let tMenge := Pos.Menge;
    let tEinheit := Pos.Einheit;
    let tSatz := Pos.Satz;
    let neuPos := (create Positionen);
    neuPos.(DokumentNr := neuPosDok);
    neuPos.(Leistung := tLeistung);
    neuPos.(Beschreibung := tBeschreibung);
    neuPos.(Menge := tMenge);
    neuPos.(Einheit := tEinheit);
    neuPos.(Satz := tSatz)
    end;
    openRecord(record('B Dokumente',number(neuDok._id))); <<--
    alert("Neues Dokument erzeugt!")

    So funktioniert es jetzt. Der Dokumente-Datensatz wird mitsamt den Einträgen der Untertabelle Positionen kopiert und auch aktiviert. Nochmals Dank an alle, die sich an der Fehlersuche beteiligt haben!

    Schönes Wochenende!
    • AxelE
    • vor 6 Jahren
    • Gemeldet - anzeigen
    Kommando zurück. Habe eben gesehen, dass Ninox die Angabe "_Id" automatisch in die jeweilige Sprachversion umwandelt, also in meinem Fall (deutsch) in "Nr". Dann kann man natürlich am besten gleich die zur jeweiligen Sprache gehörige Variante nehmen. Man muss es halt nur wissen für den Fall, dass man irgendwo in Beispielen und Codefragmenten mal mit anderen Schreibweisen konfrontiert wird.

    Und noch eine Ergänzung. Ich hatte natürlich auch das "duplicate" ausprobiert. Das funktioniert auch ganz gut, übernimmt ebenfalls die Datensätze der Untertabelle und ist in der Ausführung sogar spürbar schneller als die manuelle Variante (s. oben). Allerdings scheint(!) der interne Datensatzzeiger auch nach dem "openRecord" noch auf AltDokNr zu verweisen, obwohl schon NeuDokNr angezeigt wird. Die "Zeitstempel"-Zuweisung im Beispiel unten wird jedenfalls auf den Datensatz AltDokNr angewandt:

    let AltDokNr := Nr;
    duplicate(AltDokNr);
    let NeuDokNr := max((select 'B Dokumente').number(Nr));
    openRecord(record('B Dokumente',number(NeuDokNr)));
    Zeitstempel := now()

    Was bei dem Beispiel ganz nebenbei auffällt: Das "duplicate" verarbeitet die Datensatz-Nr wieder ohne vorherige Umwandlung (siehe erste und zweite Zeile). "popupRecord" auch. "openRecord" und "select" hingegen erwarten den Wert als "number". Ich finde das etwas verwirrend und fehlerträchtig. Oder erkennt jemand eine Logik, ein System darin? Kann ja sein, dass ich nur wieder den Wald vor lauter Bäumen nicht sehe.
    • Leonid_Semik
    • vor 6 Jahren
    • Gemeldet - anzeigen
    Hallo Axel,

    Grundsätzlich ist es so, dass alle Befehle sich auf den aktuellen Datensatz verweisen, egal ob du was neues geöffnet hast oder nicht.
    Außerdem hast du NeuDokNr schon als Nummer deklariert und brauchst das bei openRecord nicht mehr zu machen.

    Also:
    ---
    let AltDokNr := Nr;
    duplicate(AltDokNr);
    let NeuDokNr := max((select ‘B Dokumente’).number(Nr));
    let NEWRECORD:=select 'B Dokumente'[number(Nr)=NeuDokNr];
    NEWRECORD.Zeitstempel:=now();
    openRecord(record(‘B Dokumente’,NeuDokNr))
    ---
    • AxelE
    • vor 6 Jahren
    • Gemeldet - anzeigen
    Hallo Leo,

    danke für deine Hinweise. Ich habe Mitte der 80er Programmieren gelernt (ja, ich bin ein alter Sack) und tue mich nach mehr als 20 Jahren Abstinenz immer noch grundsätzlich schwer mit den neuen, objektorientierten Ansätzen der modernen Script- und Programmiersprachen (die individuellen Besonderheiten von Ninox kommen noch dazu). Der Austausch hier hilft mir ungemein und bringt mich echt weiter. Nicht nur punktuell, auf ein konkretes Problem bezogen, sondern generell.

    Besten Dank dafür!

Content aside

  • vor 6 JahrenZuletzt aktiv
  • 10Antworten
  • 4906Ansichten