none
Probleme mit einer Tabelle und deren Indexdatei RRS feed

  • Frage

  • Hallo NG,

    heute mal ein ganz anderes Problem. Es kommt immer wieder mal vor, dass eine Tabelle bzw. deren Indexdatei "zerschossen" wird. In völlig unregelmäßigen Abständen erhalte ich plötzlich beim Programmstart die Meldung:

    Fehler beim Laden der Datei - Datensatz Nr.15 "kasse <oder eines seiner Member>. Laden des Formulars oder der Datenumgebung : Die Tabelle "C:\Irgendwas\bonkasse\verkauf.dbf ist beschädigt. Die Tabelle muss repariert werden bevor sie wieder verwendet werden kann.

    Die Indexdatei ist dann meist nur noch 0kByte groß.

    Dabei handelt es sich immer um dieselbe Tabelle. Ich habe noch andere, die ähnlich behandelt werden. Also z.B. mit "ZAP" geleer. Mit denen gibt es keine Probleme. Es ist immer , wie gesagt, dieselbe Tabelle von insgesamt 12.

    Kann dies damit zusammenhängen, dass ein Feldname 12 Zeichen lang ist, der Indexname jedoch nur 10? Leider können Indexnamen nur 10 Zeichen lang werden. Der Feldname jedoch, wenn die Tabelle einer Datenbank zugeordnet ist, wesentlich länger.

    Momentan helfe ich mir damit, dass ich aus der datensicherung verkauf.dbf und verkauf.cdx hole und einfach drüberkopiere. Dann läuft es wieder. Aber ein Dauerzustand kann das nicht sein.

    Hier noch eine Kopie aus meinem Programm:

        *
        * Verkaufte Artikel wieder löschen
        *
        ThisForm.Text110.Value = ThisForm.Text120.Value
        ThisForm.Text120.Value = 0
        ThisForm.Lockscreen = .T.
        ThisForm.Grid1.Recordsource = ""

        SELECT verkauf
        SET SAFETY OFF
        ZAP
        SET SAFETY ON

        ThisForm.Grid1.Recordsource = "verkauf"
        ThisForm.Lockscreen = .F.
        ThisForm.Text111.Value = 0

    Oder lässt sich sowas anders lösen. Vielleicht mache ich das was grundlegendes falsch.

    Grüße, danke und schönes Wochenende

    Jürgen


    <--------(nur Fliegen sind schöner!)-------->

    Samstag, 7. Juli 2018 14:35

Alle Antworten

  • Hi Jürgen,

    da meine Zeiten mit nativen VFP DBs seit über 18 Jahren Geschichte sind schieße ich einfach mal ins blaue :)

    Für den Fall das Du NICHT mit 'private datasession' sondern mit der global gültigen Datensitzung arbeitest, kann ich mir vorstellen, das beim Beenden Deiner App noch der ein oder andere Cursor / Tabelle geöffnet ist.

    Um sicherzustellen dass alle Tabellenzugriffe geschlossen sind genügt eine kleine Schleife.

    Mike Lewis hat auf tek-tips mal sowas gepostet. Die u.a. Schleife stammt aus dem Link ;)

    lnWorkAreas = SELECT(1) - 1
    FOR lnI = 1 to lnWorkAreas
        USE IN (lnI)
    ENDFOR

    Eventuell sind aber auch noch ungespeicherte Daten in einem Puffer und warten darauf gespeichert zu werden. Das würde bedeuten, dass Du sowas einbauen müsstest:

    FLUSH "c:\data\customers.dbf" FORCE
    

    Den Pfad musst Du natürlich anpassen... ;)

    Den FLUSH kannst Du natürlich auch in die o.a. Schleife reinpacken. Mit ALIAS( SELECT() ) erhältst Du den Tabellen-/Cursornamen und mit FILE(FULLPATH(FORCEEXT(ALIAS(SELECT()),[dbf]))) kannst Du prüfen ob es die Tabelle gibt und ggf. flushen. FULLPATH() musst Du ggf. durch Deinen DBC Pfad ersetzen.

    Evtl. gibt es auch bessere Lösungen um sicherzustellen ob der aktuelle ALIAS eine Tabelle oder ein Cursor ist, und u.U. ist es auch egal und es kann alles geFLUSHt werden das Dir vor die Flinte kommt. Aber wie gesagt, VFP DBs sind nicht mehr mein Ding :). Olaf kennt sich da erheblich besser aus ;).

    HTH


    Gruss / Best regards
    -Tom
    Debugging is twice as hard as writing the code in the first place.
    Therefore, if you write the code as cleverly as possible,
    you are, by definition, not smart enough to debug it. 010101100100011001010000011110000101001001101111011000110110101101110011

    Montag, 9. Juli 2018 12:29
  • Hallo Tom, danke erst einmal für Deine Ausführungen. Vielleicht kann mir wirklich Olaf mehr helfen.

    Das was Du hier schreibst ist wohl die Vorgehensweise, um am Programmende alles richtig zu schließen. Also diese Schleife an das Programmende zu setzen, wenn ich das richtig verstanden habe.

    Das Problem bei mir scheint aber zu sein, dass der Fehler z.B. dann auftritt, wenn das Programm durch einen Stromausfall abstürzt. Oder eine größere Störung auf dem Versorgungsnetz. Denn wenn man es beenden kann, kann man es auch in der Regel wieder starten. Nur wenn es abstürzt, dann sind immer die Indexdateien nur noch 0 kByte groß. Es trifft auch immer, zumindest bisher, nur Tabelle, die ich temporär benütze und die daten nur kurzfristig beinhalten. Also immer wieder mit ZAP lösche. Doch was nützt das, wenn das Programm dann nicht mehr läuft.

    Früher hatte mir das McAfee - Antivirenprogramm solche Tabellen gelegentlich abgeschossen. Das konnte ich aber relativ gut nachvollziehen. Und seit McAffe weg ist (ich nehme jetzt ESET ohne Probleme), ist zumindest dieser Fehler weg.

    Nun ja. Mal sehen.

    Äh, übrigens: Kann man mit der Schleife auch direkt über ein ? - Befehl sehen, ob noch was läuft? Nur mal so zum Test.

    Schönes Wochenende

    Jürgen


    <--------(nur Fliegen sind schöner!)-------->

    Samstag, 14. Juli 2018 15:49
  • Hi Jürgen,

    klaro, alle Funktionen die Dir einen Rückgabewert liefern können entweder diesen Wert an eine Property oder Variable übergeben oder auch mit '?' direkt auf dem Screen sichtbar  gemacht werden.

    Gegen Stromausfälle kannst Du Dich nur schützen indem Du eine USV (unterbrechungsfreie Stromversorgung) vor Deinen Rechner schaltest. Die meisten USVs liefern direkt ein paar Kaltgerätesteckerkabel mit. Wie teuer es wird hängt davon ab, wie lange diese Stromausfälle und -schwankungen dauern. Bei einfachen Stromschwankungen genügen schon relativ kleine USVs an die Du heutzuteage sogar schon DSL Modems hängen kannst, und über spezielle Anschlüsse auch Laserdrucker und natürlich die Tintis.

    Soll die USV über einen längeren Zeitraum Rechner und Monitor vor Stromausfall schützen, dann wird es allerdings auch ganz schnell mal 4-stellig. Wenn es wiederum ausreicht, dass der Rechner sich ordnungsgemäß runterfahren kann, dann geht es gleich wieder etwas günstiger von statten. Achte aber beim Einkauf darauf, dass die USV über USB oder etzwerk mit Deinem Rechner kommunizieren kann, denn nur dann erhält Dein PC die Information, dass es sich runterfahren muss. Andernfalls ist wieder das Drehstuhlinterface (=DU) gefragt. ;)

    Hier findest Du mal einen kleinen Einstieg in das Thema:

    https://www.heise.de/ct/ausgabe/2018-3-Guenstige-USVs-fuer-den-Buero-PC-3941148.html

    Wieso Du temporäre Tabellen/Indizes verwahrst ist mir nicht so ganz klar. Temporär bedeutet doch eigentlich, dass Du die Daten nur kurzfristig benötigst, also kann das Zeug anschliessend auch umgehend entsorgt werden. Mir scheint es, also ob DU Dir Dein Leben nur unnötig schwer machst :)

    Ups, fast vergessen: Um zu prüfen, welche Cursor/Tabellen während der Entwicklungszeit gerade aktiv sind bracuhst Du keinen Code, das geht über das Datensitzungsfenster ;)

    HTH


    Gruss / Best regards
    -Tom
    Debugging is twice as hard as writing the code in the first place.
    Therefore, if you write the code as cleverly as possible,
    you are, by definition, not smart enough to debug it. 010101100100011001010000011110000101001001101111011000110110101101110011


    Samstag, 14. Juli 2018 17:44
  • Hallo Tom,

    das mit der USV ist schon klar. Alle meine PCs laufen über USVs. Nur das Notebook nicht ;-)

    Warum dieser Crash bei dem Notebook auch schon vorgekommen ist, kann ich nicht verstehen. Der Akku war voll!

    Wie meinst Du das mit den temporären Tabellen? Wäre es besse diese erst anzulegen, wenn sie benötigt werden, um sie danach dann gleich wieder zu löschen? Wird das Programm dann nicht langsamer?

    Ich meine, wenn das Programm beendet wird, sind sie sowieso weg. Und während des Programmlaufs werden diese ständig benützt. So wird zum Bsp.alles, was getippt wird, in einer dieser Tabellen untergebracht, manchmal darin auch sortiert, und durch einen Befehl dann abgearbeitet, danach wieder alles gelöscht.

    Ich verstehe nicht, warum es gefährlicher sein sollte, die leeren Tabellen bis zur nächsten Verwendung zu lassen anstelle sie zu löschen und dann wieder neu aufzubauen.

    Vielleicht hat es doch mit dem Index zu tun, der nur 10 Zeichen lang sein darf, der Tabellenname aber länger. Das kommt bei einer der drei temporären Tabellen vor und genau diese erwischt es zu 95%.

    Ich werde manl versuchen, den Tabellennamen zu verkürzen. Vieleicht bringt das etwas.

    Übrigens habe ich die Schleife

    lnWorkAreas = SELECT(1) - 1 FOR lnI = 1 to lnWorkAreas USE IN (lnI) ENDFOR

    ans Programmende gehängt. Schaden kann es ja nichts ;-)

    Gruß Jürgen


    <--------(nur Fliegen sind schöner!)-------->


    Sonntag, 15. Juli 2018 17:43
  • Hi Jürgen,

    ich arbeite leider nicht mit selbst erstellten temporären Tabellen auf VFP-Basis. Mein täglich Brot besteht aus dem Handling von 40-60 Cursorn die mit SQL Selects und Views befüllt werden und diese Cursor werden zur Laufzeit permanent verändert, geschrieben, entsorgt und neu generiert/befüllt und das bei einigen Anwendern tausendfach am Tag mit hunderten von Anwendern gleichzeitig.

    Zeitkritisch ist immer nur das bereitstellen von Auswahldaten auf Basis von vom Anwender definierbaren Filtern. Die sich daraus ergebenden SELECTs mit JOINs über ein dutzend Tabellen müssen immer wieder optimiert werden. Diese Optimierungen enden auch mal in neuen Untertabellen oder dem entfernen von Normalformen einfach um wieder eine bessere Perfomance zu erreichen. Letztendlich also ein wiederkehrendes hinterfragen der eigenen Vorgehensweisen und des damit einhergehenden Codes.

    Das was Du als temporäre Tabellen beschreibst wären bei mir einfach nur Datencursor die ich niemals in eine reale Tabelle schreiben würde. Diese Aufgabe überliesse ich grundsätzlich dem Fuchs, denn Cursor legt dieser immer in C:\Users\<USERLOGIN>\AppData\Local\Temp ab und das geschieht mit der von VFP gewohnt hohen Geschwindigkeit. Erkennbar sind diese ausgelagerten Cursor an ihrem Namensaufbau der üblicherweise mit dem Suffix '.TMP' endet und auch bei Deiner App entstehen dürfen.

    Wenn Du nun anstelle der temporären Tabellen auf Cursor umstellst, dann sollte das bei ein paar tausend Datensätzen keine spürbaren Geschwindigkeitseinbussen mit sich bringen. und sollte Deine App mitten drin abrauchen, dann hat dies keinerlei negative Auswirkungen auf Indizes o.ä. den Cursor kennen sowas gar nicht.

    Stellt sich also die Frage, warum Du die Indizes benötigst. Hast Du da tatsächlich abertausende von Daten Die du ständig durch die Mangel drehen mußt oder hast Du das zu Beginn einfach mal so gemacht weil Du das irgendwo gelesen hast und arbeitest heute einfach immernoch nach diesem Schema? Falls dem so sein sollte, dann wäre eine Umstellung auf Cursor definitiv eine Überlegung wert.

    Und ohne dem guten alten Fuchs ans Bein pinkeln zu wollen...vllt. brächte Dir ein Umstieg auf die Lite Version vom SQL Server eine höhere Datensicherheit.

    Aber für mich als Aussenstehender ist das natürlich leichter gesagt als von Dir getan :) aber ab und an bringt das abschneiden alter Zöpfe tatsächlich Vorteile mit sich :)))

    JM2C


    Gruss / Best regards
    -Tom
    Debugging is twice as hard as writing the code in the first place.
    Therefore, if you write the code as cleverly as possible,
    you are, by definition, not smart enough to debug it. 010101100100011001010000011110000101001001101111011000110110101101110011

    Montag, 16. Juli 2018 11:14
  • Hallo Tom, mit Deinen Erläuterungen hast Du Dich ja wieder mächtig ins Zeug gelegt. Danke.

    Hier nochmal zur Erklärung, wie ich das mit der Tabelle mache:

    Ich habe eine Tabelle, die eine Preisliste für Essen und Getränke enthält. Die heißt einfach preise.dbf. Dann gibt es eine, die heißt verkauf.dbf und ist normalerweise leer.

    Bei jedem Artikel, der nun verkauft wird, wird dieser in die Tabelle verkauf.dbf geschrieben. Das ist eigentlich trivial. Ist eine Bestellung zu Ende (egal wieviel Artikel), dann werden alle in der Tabelle verkauf.dbf in der Tabelle umsatz.dbf verbucht und auf einem Bondrucker ausgedruckt. Danach wird verkauf.dbf für den nächsten Kunden wieder geleert.

    Gibt man nun Artikel durcheinander ein, dann möchte man vor dem Ausdruck gleiche Artikel direkt hintereinander ausdrucken, damit die partiell abgeschnittenen Bons z.B. zwischen Speisen und Getränken getrennt werden können und man diese hinterher nicht erst noch sortieren muss. Deshalb die Indexdatei.

    Die Anzehl der Artikel liegt pro "Kunde" immer so zwischen 1 und 20.

    Da ich bisher noch nie mit Cursoren gearbeitet habe, tue ich mir da etwas schwer. Ich muss jetzt erst einmal den Unterschied zwischen Cursor und Tabelle lernen und wie man mit dem Cursor diese Umsortierung macht, falls das damit überhaupt möglich ist.

    Du musst wissen, dass ich mir VFP selbst angeeignet habe. Eigentlich habe ich früher nur in Assembler programmiert. Dann kam Foxpro 2.5 (noch im DOS-Look) und ich wurde von meinem Chef gebeten, damit eine Gefahrenstoffverwaltung für unser Institut zu programmieren, was ganz gut geklappt hat und ich hier die ersten Begegnungen mit dem Fuchs hatte. Und weil das so gut funktioniert hat drückte man mir gleich noch eine kleine Buchhaltung für das Sekretarieat auf (bevor R/2 von SAP eingeführt wurde). Dann kam VFP7. Ich schrieb dann für unseren Verein das erste Programm mit grafischer Benutzeroberfläche, mit dem man die Starts und Landungen der Flugzeuge verwalten kann. Dieses Programm läuft übrigens seit über 10 Jahren und jeder, der damit arbeitet, ist begeistert (soviel Eigenlob, mehr nicht (grins)).

    Und jetzt kämpfe ich mit dem aktuellen Programm, mit dem wir unsere Essen- und Getränkebons für die Flugtage erstellen. Bei all den anderen hatte ich keine solchen Probleme. Andere ja, OK, aber die wurden alle (auch mit Hilfe von Forumsmitglieder) behoben bzw. bseitigt.

    Vielleicht lies Olaf oder Woody mal diese Zeilen und hat noch einen Vorschlag oder eine Idee.

    Wie gesagt: eigentlich läuft alles sehr gut. Nur halt im Falle von .....  wenn es mal kracht ;-(

    Gruß Jürgen


    <--------(nur Fliegen sind schöner!)-------->

    Dienstag, 17. Juli 2018 17:17
  • Hi Jürgen,

    In VFP ist ein Cursor eine temporäre Tabelle und stellt ein Gruppe von Daten dar (CURrent Set Of Records). Zum Erstellen eines Cursors benötigst Du entweder eine SQL Abfrage 

    SELECT meinFeld FROM meineTabelle INTO CURSOR meinCursor READWRITE

    oder erzeugst ihn zu Fuß

    CREATE CURSOR meinCursor ( meinFeld c(10) ) 

    und fügst mit

    INSERT INTO CURSOR ( meinFeld ) VALUES ( [blablabla] ) 

    einen Datensatz ein.

    Bei CREATE ist der Cursor automatisch READWRITE und kann jederzeit beschrieben werden. Beim SELECT ist das erzeugte RecordSet automatisch schreibgeschützt. Erst mit der Klausel READWRITE (verfügbar seit VFP7) wird der Schreibschutz aufgehoben.

    Interessant an Cursorn ist, dass sie sich weitestgehend wie Tabellen verhalten. Deswegen funktioniert bspw. auch so etwas:

    CREATE CURSOR meinCursor( meinFeld1 C(10) )
    ALTER TABLE meinCursor ADD meinFeld2 i
    

    Je nach Datenmenge eines SELECTs legt VFP (wie in meiner vorherigen Mail schon geschrieben) automatisch eine temporäre Tabelle im entsprechenden USER-TEMP Ordner an. Ab und an ist der Fuchs jedoch der Meinung, dass er für die generierte Datenmenge keine temporäre Tabelle benötigt und läßt die Erzeugung der USER-TEMP Datei einfach weg. Ist zwar eigentlich OK, aber je nachdem was Du mit dem RecordSet im Anschluß anstellen möchtest kann das unangenehm enden. Wenn Du das gezielt vermeiden möchtest steht Dir die Option NOFILTER beim SELECT zur Verfügung. Dann legt VFP grundsätzlich eine Datei in USER-TEMP an.

    Die Ähnlichkeit eines Cursors mit einer Tabelle liegt daran, dass VFP ihn tatsächlich als Tabelle im USER-TEMP Verzeichnis speichert (siehe vorherige Antwort) und somit funktionieren viele Dinge analog einer Tabelle. Du kennst halt nur nicht den Tabellennamen sondern nur seinen von Dir definierten Alias. Allerdings kannst Du Dir im CommandWindow mit ?DBF() Dir den physikalischen Namen anzeigen lassen.

    Einen mit READWRITE erstellen SELECT kannst Du auch ganz normal mit Indizes versehen. Im USER-TEMP Ordner gibts dann halt nur eine weitere Datei.

    Und da die USER-TEMP Tabellen mit UNIQUE-Namen versehen sind interessieren sie nach dem schliessen Deiner App (egal ob absichtlich oder unerwartet) den Fux beim nächsten Start in keiner Weise, denn dann werden durch Deinen SELECT oder CREATE automatisch wieder neue Tabellen in USER-TEMP erzeugt und das Beste daran ist, VFP macht das für Dich unter der Hand und Du musst eigentlich nur dafür sorgen, das USER-TEMP regelmäßig aufgeräumt wird.

    HTH


    Gruss / Best regards
    -Tom
    Debugging is twice as hard as writing the code in the first place.
    Therefore, if you write the code as cleverly as possible,
    you are, by definition, not smart enough to debug it. 010101100100011001010000011110000101001001101111011000110110101101110011

    Mittwoch, 18. Juli 2018 07:23
  • Hallo Jürgen,

    ich war schon lange nicht mehr da, aber ihr seid ja schon wesentlich weiter. Ich bins, ich fange hier jetzt mit neuem Profil an, weil mein bisheriges mit einer nicht mehr vorhanden Mailadresse verbunden war. Mal sehen, ob ich dazu von MSDN Seite her Hilfe bekomme, aber weniger wichtig.

    Ich pflichte Tom bei, nutze Abfragen SELECT...INTO CURSOR und Du musst Cursoren auch nicht per CREATE CURSOR erstellen, das ist sowieso das tägliche Brot von VFP SQL und kostet überhaupt nicht die Welt.

    Es gibt keinen Unterschied von Cursoren zu Tabellen, Cursoren sind Tabellen, nur nicht permanent. Und se haben den Vorteil ohne einen extra dazu angelegten DBC Eigenschaften wie lange namen, Default Werte etc haben zu können.

    Code von so einen Spezi wie Dir hatte ich auch schon, und ein Arguement für diesen Entwickler war, den letzten Zustand bei Abstürzen eben zu haben und z.B. Reportfehler nachvollziehen zu können, etc.

    Und wegen Defekten habe ich da eine Kopie aller leerer heiler Tabellen vorgesehen, um die Reparatur einfach durch vollständigen Ersatz aller Dateien zu erledigen, ist doch eine ganz logische Lösung, die Vorlagetabellen werden immer nur als Kopiervorlage genutzt, müssen u.U. auch mal in ihrer Struktur aktualisiert werden, aber gehen deswegen auch nie defekt. Und wenn ich das langfristig weiter betreut und in Form gebracht hätte, hätte ich mehr und mehr Tabellen davon eliminiert durch die Abfragen, die diese Taebllen erstellen und damit ausmachen.

    Vor allem aber für die beste Performance sollte man von DBFs für temporäre lokale Einzeluserdaten absehen. Dafür sind Cursoren da! Wenn Du mit Deiner Denke allerdings mit Cursoren statt Tabellen arbeitest, kommst Du trotzdem nicht so weit, weil all Dein Code einerseits darauf ausgelegt ist die Tabellen bleiben bestehen, andererseits, Du kannst die DBFs innerhalb jedes Formulars auch in unterscheidlichen Datensitzungen nutzen.

    Du mußt Sie nur mit ZAP leeren und kannst sie neu befüllen. Nun, Cursoren "befüllst" Du, indem Du sie erzeugst, per Abfrage INTO CURSOR. Und die Cursorstruktur ist dann vollautomatisch genau die für das Ergebnis benötigte, das ist ein entscheidender Vorteil. Es ist das normalste von der Welt für VFP Cursoren zu erzeugen. Deswegen braucht man Sie auch nicht in Dateiform, sie ergeben sich eben einfach, was Du benötigst sind die SQL Abfragen. Code eben, so wie sich das für Software gehört, gerade für DB Software, lokal hast Du Ergebnisse von SQL im Speicher in für das Frontend gedachtem Format, für VB ADO.Recordsets, für C# z.B. Ein DataContext mit DataTables für VFP eben Cursoren. Auch SQLExec erzeugt Dir was? Cursoren. Views? Cursoren. Letztlich greifst Du auch auf DBF selbst über das gemeinsame Grundkonept zu: die Workarea. Man könnte schon eher andersherum sagen: DBFs sind auch nur Cursoren, nur eben persistiert auf Festplatte.

    Tabellen sind für permanente Daten und nur für solche.

    Du kannst dann in Deine DBF Welt zurückkehren und den einzigen Vorteil nutzen, solche lokalen DBFs aus verschiedenen Datensitzungen zu sehen, indem Du einen Cursor dann für den Fall per COPY TO auf Platte schreibst. Das dauert dann, nicht unbedingt merklich, wie bisher halt, mit SSD recht wenig. Aber Cursoren sind sowas wie im Speicher gehaltene Tabellen, solange Du SYS(3050) nicht zu niedrig ansetzt, und deswegen kostet deren Erstellung quasi Null Zeit. Selbst eine schon vorhandene leere DBF Datei kostet Dich mehr Zeit, weil Sie eben von Disk gelesen wird, Cursoren finden nur in dem Extremfall den Weg auf die Festplatte, wenn Sie größer werden. Oder wenn Du eben ganz bewusst COPY TO machst.

    Du verzichtest auf das Hauptarbeitspferd von VFP mit dem Verzicht auf Cursoren, nämlich in Memory DBFs. Es sind DBFs, deswegen gibt es keine Codeanpassung für den Zugriff auf Cursor vs DBF Felder, Du kannst auch SQL auf Cursoren anwenden, es sei denn es sind nur Filtercursor, aber die kannst Du mit dem Zusatzwörtchen READWRITE von SQL-Select ...INTO CURSOR AliasName READWRITE  verhindern, was Dir sowieso dann überhaupt wie für Deine bisherigen lokalen DBFs ermöglicht die Cursoren, die aus Abfragen entstehen auch im Nachhinein noch zu ändern, also in dem Ergebnis als Nachschritt noch ein UPDATE oder REPLACE zu machen, weitere Eingaben per INSERT oder APPEND anzufügen, etc. wie das eben alles auch mit DBFs geht.

    Übrigens: Da Cursoren bei SELECT INTO immer wieder komplett neu entstehen sind sie per se auch erst einmal komplett ohne Index. (Man kann wie eben gesagt auch Daten per INSERT INTO CursorName zufügen, oder per APPEND, ganz wie bei DBFs, 100% kompatibel, da es DBFs sind!)

    Da haben DBFs nun auf den ersten Blick den Vorteil, keine INDEX ON Code mehr zu benötigen, aber ein per ZAP geleerter DBF mit entsprechend geleertem CDX kostet Dich dennoch bei befüllen mit neuen Daten immer wieder Indexierungszeit, der Index wird ja mit jedem Datensatz, den Du in den DBF speicherst aktualisiert und auch auf Platte geschrieben. Cursoren als Tabellen im Speicher sind da schneller, obwohl Du den ganzen INDEX ON Code auch noch laufen lassen musst.

    Außerdem: Im Cursor hast Du zunächst mal die Daten selbst, die mit den Indizes aus Deinem  Backendtabellen optimiert ausgelesen wurden, typischerweise genau all die Sätze, die Du brauchst, in der Sortierung, die Du brauchst, weswegen Du nicht einmal unbedingt einen Index im Cursor benötigst. Die Rushmoreoptimierung der Abfrage des Backend ist bereits getan zur Erstellung des Cursorergebnisses.

    Wenn, dann ist ein INDEX ON nachdem alle Daten da sind auch noch ein Tacken effektiver als ein bereits bestehender Index, der mit jedem neuen Datensatz aktualisiert wird, vor allem, weil das alles eben nur in RAM passiert und in einem Rutsch. SET TALK OFF oder eine größere Anzahl an Datensätzen per SET ODOMETER ist dann schon fast das wichtigste, damit die Indexierung nicht lange dauert weil ständig in der Statusbar angezeigt wird welche Datensatznummer gerade indexiert wird und das schon mehr Bytes im Grafikspeicher bewegt als im Objektspeicher für DBF, CDX und FPT zusammen.

    Nachtrag: Häufige Defekte in lokalen DBF Dateien rphren im übrigen nie von oplocks, die passieren nur über Netzwerkprotokoll, was hier wegfällt. Die einzig denkbaren Urscahen sind alte fehleranfällige HDD oder Antivirus. Es ist trügerisch anzunehmen ESET sei da besser als anderes. Mit jedem Virenscanner sollte man DBF Dateien ausnehmen, es würde sowieso früher oder später sehr offensichtlich wenn sich Viren in eine DBF einnisten wollten, sei es die DBF wird durch headerdefekt nicht mehr also solche erkannt, sei es eine sich am Ende verlängerte DBF ist über den nicht mehr dazu passenden Reccount im Header genauso defekt oder sei es ein Virus überschreibt im Bauch Daten. Deswegen wird auch kein Virenentwickler je DBfs als Vehikel oder Zwischenlagerundgsdatei benutzen. 

    Jede Antivirussoftware, die mir bisher unterkam hat die nötigen Ausnahmeregeln und man sollte sie für die DBF/CDX/FPT Dateiendung auch nutzen. Es ist shr wahrscheinlich, dass Deine Proleme genau daher rühren, denn Alterungseffekte von HDD machen sich nicht erst sporadisch und dann immer stärker bemerkbar. Gerade wenn einer SSD die eingebaute Over-Provisioning Reserve ausgeht geht es rasant bergab und auch was klassische Magnetlaufwerke angeht habe ich da nie langsame Degradation erlebt. Der Effekt von dem Nachsehen von Antivirussoftware, ob mit den neu geschriebenen Bytes auch alles in Ordnung ist mag sich beißen mit VFPs Lockingmechanismus, der sowieso im allgemeinen nicht die Stelle sperrt, die der sperrende schreiben will und die damit auf Gegenseitigkeit beruht, Gegenseitiges Einverständnis eines anderen VFP Prozesses der die Sperre sieht und damit weiß in welchem Bereich er tatsächlich nicht schreiben darf. Antiviurssoftware hat dieses Detailwissen um DBFs nicht und kann im Zweifelsfall genau weil es da Aktivität in Sperrungen von Bytes sieht, die in einem Offset 2GB-RECNO() liegen der gar nicht zur DBF Datei gehört, solange sie nicht gerade in die Größenordnung kommt. Und wer weiss warum, aber offenbar führt genau das oftmals zu falschem intervenieren.

    Tschüß, Olaf.

    Montag, 23. Juli 2018 13:19
  • Hallo Olaf,

    jetzt hast Du mich mit Deiner ausführlichen Antwort fast erschlagen.

    Also mit Cursoren tue ich mich sehr schwer, weil ich davon, gelinde gesagt, keine Ahnung habe. Ich habe bisher nur verstanden, dass es sich quasi um eine temporäre Tabelle handelt. Bisher habe ich nur zwei Zeilen hinbekommen und das Ganze mal getestet:

    *
    * Cursor testen
    *
    * Cursor für verkauf.dbf erstellen. Hier mal vvv genannt
    *
    v1 = "Wurst"    && Artikel
    v2 = 12            && Artikelnummer
    v3 = .T.        && Druckflag
    v4 = .F.        && Küchenflag
    v5 = 1            && Menge
    v6 = 2            && Steuer
    v7 = 2.20        && Preis

    CREATE CURSOR vvv ( artikel c(20), artikelnummer n(2), drucken L, kueche L, menge N(2), mwst N(1), preis Y )
    INSERT INTO vvv ( artikel, artikelnummer, drucken, kueche, menge, mwst, preis ) VALUES (v1, v2, v3, v4, v5, v6, v7)

    Das bringt zumindest mal keine Fehlermeldung (syntaktisch gesehen).

    Wie ich allerdings diese Daten dann, nachdem ich mehrere Sätze davon "durcheinander" eingegeben habe, nach Artikelnummern sortieren kann, weiß ich noch nicht. Und wie ich diese dann in einen vorhandenen Bericht einbauen kann, erst recht nicht. Mit einer Tabelle ist das recht einfach (Felder in den Report einfügen und Daten aus der Tabelle zuordnen). Vielleicht mit einem Cursor auch, wenn man es erst einmal verstanden hat.

    Mal sehen, ob ich darüber Literatur finde.

    Übrigens, bevor ich es vergesse: Rainer Becker schrieb, dass am 18.9. in Stuttgart ein Entwicklertreffen stattfinden soll. Falls von Euch, Olaf oder Tom, auch jemand dortsein sollte, werde ich mich anmelden (kostet das eigentlich etwas?). Dann könnte ich mein Programm ja mal auf einem Notebook mitbringen. Vielleicht finde ich dort etwas Unterstützung. Vielleicht ist dort aber auch so viel los und es werden nur spezielle Dinge behandelt, dass man für mich "Greenhorn" gar keine Zeit hat.

    Oder soll ich mal versuchen, die temporären Tabellen beim Programmende zu löschen und beim Programmstart wieder neu programmatisch erzeugen? Man kann ja dann evtl. stehengebliebene "Reste" damit überschreiben.

    Nur, ich möhte einfach mal verstehen, warum nur die mit ZAP geleerten temporären Tabellen zerstört werden und nicht die anderen, die die eigentlichen Daten enthalten.

    Und nochmal die Frage mit dem abgeschnittenen Indexnamen, der um zwei Zeichen kürzer ist als der Feldname. Das geht mir einfach nicht aus dem Kopf. Vielleicht sollte ich einfach mal den Feldnamen kürzer machen.

    Trotzdem noch einmal danke für die umfangreiche Ausführung. Ich werde diese noch mehrmals studieren. Bis ich alles kapiert habe ;-))

    Gruß Jürgen


    <--------(nur Fliegen sind schöner!)-------->

    Mittwoch, 25. Juli 2018 16:49
  • Du hast doch schon Daten, die Du abfragen willst.

    Wenn Du Deine bisherigen DBF füllst, wie machst Du das? Machst Du ein
    INSERT INTO lokale.dbf   SELECT  ... FROM Datenbanktabelle?

    Na, dann machst Du jetzt SELECT ... FROM Datenbanktabelle INTO CURSOR lokalerCursor READWRITE

    Tschüß, Olaf.

    Mittwoch, 25. Juli 2018 18:31
  • Es ist auch einfach eine bestehende Datenbanktabelle strukturell zu kopieren, Du brauchst Dir nicht lauter CREATE CURSOR aufbauen, Cursoren sind Abfrageergebnisse, sie entstehen von ganze alleine in der Struktur, die für das Abfrageergebnis benötigt wird.

    SELECT * FROM Tabelle INTO CURSOR Cursorname WHERE .F. READWRITE erstellt Dir einfach einen leeren Cursor.

    Aber Du brauchst keine leeren Tabellen, in die Du Abfrageergebnisse zusammensammelst, Du brauchst SQL SELECT Abfragen und das ist alles, die Ergebnisse davon sind Cursoren. Sobald Du mit SQL arbeitest, arbeitest Du schon die ganze Zeit mit Cursoren. Denn selbst ohne INTO CURSOR erhältst Du einen Cursor namens Query. Das ist auch ein Cursor. Sobald Du einen View aufmachst mit USE YourView hast Du neben den DBFs noch den View Cursor.

    Die einzige Art um Cursor herumgekommen zu sein ist Deine Daten per USE oder in der Datenumgebung zu öffnen und nur darauf direkt herumzuewerkeln, nie Joins zu machen, etc.

    Wenn Du so arbeitest, wozu dann überhaupt noch lokale DBFs? Du wirst Du Daten nicht dahin per SCATTER GATHER kopieren, oder per APPEND.

    Tschüß, Olaf.

    • Bearbeitet OlafDoschke Donnerstag, 26. Juli 2018 17:01
    Mittwoch, 25. Juli 2018 18:34
  • Um nochmal auf das Eingangsproblem einzugehen:

    Da Du verkauf sowieso nur leer haben möchtest ist ZAP schon richtig. Und ZAP darf sowohl DBF als auch CDX nur bis zur headergröße abschneiden, wenn der CDX dabei 0 bytes lang wird ist da was faul. Ich tippe dann ist der CDX schon vorher defekt und VFP erkennt nicht das CDX headerende.

    Lösung mit überschreiben aus backup geht, klar. 

    Wenn ZAP so immer wieder schief geht, dann vielleicht wegen Antiviruseingriff, dann könntest Du auch die leere verkauf.dbf weglegen und wiederherstellen, das war ja schon sowieso schon meine Idee für die Integrität Deiner lokalen leeren DBFs. Ich kann mir nur vorstellen, dass der ZAP schon an einem Defekt vor dem ZAP scheitert, denn das ZAP ist wirlich ein einfacher Vorgang, der die Header aller an der Tabelle beteiligten Dateien beibehält und die Dateien darauf kürzt.

    Und nein, das scheitert nicht an der Indexnamenslänge. Ja,die ist auch für DBC Tabellen nur 10, heißt nur, dass der Index Tagname dann nicht wie das Feld heissen kann, muss er aber ja nicht. Der Ausdruck für den Index kann länger sein, ich wüßte nicht einmal eine beschränkung dafür, die Indexbreite ist maximal 240 byte. Aber all das ist völlig egal bei dem Thema die CDX Datei per ZAP auf 0 bytes zu bringen. Oder sind 0kb, wenn Du mal genauer in die Properteis schaust dann noch weniger als 512 bytes o.ä. Die genaue Dateilänge wäre da schon interessant 0 KB in der Explorer Spalte für Dateigröße muss noch nicht 0 Byte heißen.

    Das ZAP machst Du ja erst nach starten des Formulars, oder? Dann ist der Defekt beim starten des Formulars noch aus der hinterlassenen Situation in verkauf. ZAP doch bei Formularende. Ich denke beim letzen Schließen der verkauf.dbf kommt der Fehler rein. Wenn als letzte Aktion per ZAP alles was bosher noch nicht in DBF oder CDX gesichert ist sowieso entfällt, kann ich mir vorstellen hinterlässt Du den DBF sauberer, also läßt Du den letzten Verkauf stehen.

    Der eigentliche Fehler dürfte eher beim verlassen des Formulars sein und zeigt sich dann beim nächsten Start. Tabellendefekte machen sich immer erst beim öffnen bemerkbar. Was zum Schluss weggeschrieben wird, wird dabei nicht validiert, eine Tabellenvalidierung findet immer beim Öffnen statt.

    Insbesondere Ausschalten des PC vor Beenden Deiner Anwendung kann gerne zu solchen Defekten führen. Deine Anwendung wird vom OS beendet, schreibt dann noch schnell alle Buffer weg, aber das OS fährt dann u.U. schon die Platte runter auf die noch was im letzten Moment gespeichert werden soll. Der OS Vorgang des herunterfahrens sollte zwar zuerst alle Prozesse gekillt haben, bevor es auch die Hardware herunterfährt, aber da das alles Zeitnah passiert kann ich mir gut vorstellen, dass da manchmal genau dieselben Defekte entstehen, wie durch Stromausfall.

    Es ist schön öfter berichtet worden, dass ein PACK mit zu schneller anschließender Öffnung der per PACK gekürzten DBF zu Fehlern führt. Da ist irgendwas in der VFP Runtime, was mit dem Filesystem auf eine legacy Weise agiert, so dass irgendwelche Flushvorgänge erst verzögert passieren. Oder VFPs eigenes Caching steht da im Weg. 

    Wenn Du Dich da auf das Aufräumen vom OS bei herunterfahren verlässt, wäre das jedenfalls eine Erklärung für mich, DBFs sind da empfindlich was noch nicht wegeschriebene Änderungen angeht, und VFP ist faul damit, um im allgemeinen Zeit zu sparen.

    Tschüß, Olaf.

    Sonntag, 29. Juli 2018 07:37
  • Hallo Olaf,

    Du hast mich fast erschlagen mit Deinen Ausführungen. Ich habe mir Deine Antwort mehrmals durchgelesen.Ich denke, ich mache das erst einmal mit dem Überschreiben aus dem Backup.

    Wäre auch folgendes denkbar? Wenn der Fehler auftritt, hat dieser doch sicher auch eine Fehlernummer. Kann man dabei auch feststellen, welche DBF kaputt ist? Dann müsste man doch die entsprechende quasi automatisch aus dem Backup ersetzen können und ein RESUME durchführen. Ein Anwender sollte dann eigentlich von dieser "Reparatur" gar nichts mitbekommen.Wäre ein Test wert.

    Gruß Jürgen

    PS: Danke nochmals für Deine Mühen!


    <--------(nur Fliegen sind schöner!)-------->

    Mittwoch, 8. August 2018 09:04
  • In der Fehlermeldung selbst steht doch die Tabelle drin.

    Außerdem machst Du ein USE einer bestimmten Datei, die dann einen Fehler auslöst. Dann ist doch klar, welche Tabelle. 

    Mal abgesehen davon, dass ich nicht weiß, ob Du je erzählt hast welcher Code welchen Fehler verursacht, nur dass deine Indexe defekt werden. OK, nochmal zurückgescrollt, Du hast einen DBF Namen in der Meldung, ein Datensatz Nr X einer SCX wird genannt, wenn Du das SCX als Tabelle öffnest, wirst Du darin den Datensatz finden, der in der Datenumgebung des Forms die genannte DBF Datei repräsentiert und dafür sorgt, dass sie geöffnet wird. Was defkt ist, ist aber nicht der SCX Datensatz, sondern eben die DBF.

    Mal abgesehen davon, dass AERROR bei Fehlern die mit Tabellen zusammenhängen in Spalte 3 des Fehlers den Namen der betroffenen Workarea angibt, das Hilfethema zu AERROR verweist außerdem noch zu SYS(2018), was Du wegen AERROR allerdings eigentlich nie brauchst, der AERROR Eintrag ist typischerweise Mixed Case, kann auch schon mal der Name einer Datei sein, was auch immer in der Fehlermeldung ein Detail ist.

    Insofern ja, Du kannst im Fehlerfall eine Tabelle mit einem Backup austauschen, mit dem Nachteil, dass klarerweise das Backup nicht den aktuellen Datenbestand hat und je nachdem an welcher Stelle der Fehler passiert es Dir wenig bis gar nichts nutzt eine leere aber heile DBF zu haben, wenn Du das aktuelle Abfrageergebnis brauchst. Innerhalb einer SQL Abfrage kannst Du auch definitiv nicht kurz mal einen Abstecher machen, Dateien austauschen und dann weiter abfragen. Im Zweifelsfall weißt Du gar nicht an welche Stelle im Code Du zurück müsstest um mit der reparierten DBF weiterzumachen, indem Fall definitiv nicht, ein Return von dem Fehler läßt die Datenumgebung des Formuars nicht weiter laufen. Und daneben geht Dir durch das Backup ja verloren was in der Anwendungssitzung chon an Daten hereingeflossen war.

    In dem Fall, von dem ich sprach, hat es gereicht einmal bei Programmstart alle lokalen DBFs mit dem Backup bzw. "Template" der heilen und leeren DBFs zu initiieren. Das war vergleichbar mit der Situation ganz leer ohne Cursoren zu beginnen, wie das ja auch normal ist. Nur da macht es Sinn, nicht jedesmal. Genauso wie man eine DBF der zentralen Datenbank nicht per 'Restore aus dem Backup ersetzt und nicht nur dem aktuellen User seine heute erwirtschafteten Daten unterm Arsch wegzieht, sondern auch allen anderen.

    Du hast noch Fragen offengelassen, wie Du überhaupt lokale DBFs befüllst. Der ganz normale Weg mit Daten umzugehen ist doch eine zentrale Datenbank zu haben und von dort aus Daten abzufragen, mit Views, mit SQL Into Cursor, vielleicht auch mal mit USE der zentralen DBFs im Shared Mode direkt an Ort und Stelle, aber das ist dann eben schon sehr speziell VFP, das geht schlecht mit einem SQL Server Backend. Aber die einzigen lokeln DBFs, mit denen ich noch hantiere aren sowas wie Konfigurationsdaten oder Errorlog oder sonst etwas an Metadaten, gerade alles, was nur mit dem einen Client zu tun hat.

    Mir ist insofern immer noch nicht klar, wenn Dir SQL ein Buch mit Sieben Siegeln ist, wie Du dann von zentralen DBFs in die lokalen kommst? Machst Du da ein COPY oder APPEND mit FOR Bedingung? Machst Du ständig Dateikopien und schickst die in der Weltgeschichte herum?

    Seit Vista ist alleine schon bekannt das ein PACK, was eine DBF neu erstellt, die Daten ohne Löschmrkierung in die neue DBF holt und Dateien dann umbenennt Probleme hat, weil das OS da Dinge im Filesystem verzögert, VFP schon mit dem PACK fertig ist und anschließend ein USE nicht klappt, weil die neue Datei eben doch noch nicht da ist. Dein ganzer Mechanismus könnte genau an diesen Lazy Load und Caching etc. Mechanismen des OS leiden, Cursoren leiden darunter nicht.

    Defekte live zu lösen wird nach meinem Gutdünken eher zu Folgeproblemen führen. Ich hab auch insofern nicht die Erfahrungsschätze, was da möglich wäre, weil defekte sich in normalen Anwendungen auf die Backendtabellen beschränken, die Du garentiert nciht mit leeren Kopien überschreibst und lokale Daten, also Cursoren, sowieso dann weg sind, wenn das Programm sich beendet, da ist nie etwas zu reparieren.

    Tschüß, Olaf.

    • Bearbeitet OlafDoschke Samstag, 11. August 2018 18:23
    Samstag, 11. August 2018 18:06
  • Hallo Olaf,

    ich muss ab morgen für bis zu zwei Wochen weg. In dieser Zeit kann ich sowieso nichts machen.

    Wenn ich zurück bin schreibe ich mal mit Programmauszügen, wie die eine Tabelle, die es meistens erwischt, gelöscht, gefüllt und ausgelesen wird usw.

    Danke und Gruß und schönen Sonntag

    Jürgen


    <--------(nur Fliegen sind schöner!)-------->

    Samstag, 11. August 2018 19:48
  • So, nach meinem Kurzurlaub hatten wir Flugtag. Da habe ich das Programm eingesetzt. Und zwar auf zwei Notebooks. Einem 3 Jahre alten HP Compaq und einem 10 Jahre alten Maxdata. Auf jedem PC habe ich vier Programminstanzen installiert, so dass bei einm Crash man einfach die nächste noch funktionsfähige starten konnte und Abends nach dem Ansturm die Datensicherung mit einer intakten Instanz wieder einlesen konnte. Gesichert wurde bei jedem Verkaufvorgang. Ach ja, es handelt sich hier um ein Programm zum Erstellen von Bons für Bier und Würste usw.

    Beim HP gab es keine Ausfälle. 2 Tage nicht. Alles lief wie geplant. Sicherheitshalber waren beide Anlagen mit einer USV gegen Stromausfall abgesichert.

    Beim Maxdata gab es zwei Ausfälle. Einmal ist der FI rausgegangen (eine Fritteuse ist abgebrannt) und einmal stolperte jemand über das Netzkabel des PC. Da war er sofort aus, da der Akku defekt war. Warum das Programm beim Auslösen des FI auch abschmierete kann eigentlich nur an einer Überspannumng liegen, die dabei aufgetreten ist. Denn die USV tat ihren Dienst.Beim Startversuch der ersten Instanz trat folgender Fehler auf:

    Leider steht hier nicht, welche Datei betroffen war. Also kopierte ich zunächst die verkauf.dbf zusammen mit verkauf.cdx aus dem Original zurück, da diese nur temporär verwendet werden. Danach startete ich das Programm wieder und es kam:

    Hier wurde mir gezeigt, welche Tabelle es außerden noch erwischt hatte. Hier gibt es auch keine Indexdatei und auch diese ist temporärer Art. Also konnte ich sie ebenfalls durch ein Original ersetzen.

    Nächster Startversuch. Und siehe da, das Programm ließ sich wieder starten. Allerdings war die Umsatztabelle (ohne Indexdatei) leer! Das kann ich jetzt gar nicht verstehen.

    Dasselbe habe ich bei der zweiten kaputten Installation gemacht. Und auch da kamen die beiden erwähnten Meldungen, ich ersetzte die Dateien durch die Originale und auch hier stellte ich nach dem 3. Programmstart fest, dass alle Umsätze weg waren. Nur aus den Datensicherungen konnte ich diese wieder herstellen.

    Jetzt frage ich mich, warum die Umsatztabellen gelöscht wurden!

    Was kann ich tun, dass bei einem Stromausfall oder Programmabsturz so etwas nicht passiert? Soll ich die Tabellen nicht bereits beim Programmstart alle öffnen (ich mache dies über Ansicht -> Datenumgebung), sondern nur für den kurzen Moment, wenn sie benötigt werden? Das würde dann die Wahrscheinlichkeit eines Datenverlustes auf diese kurze zeitspanne begrenzen.

    Und warum ist die Umsatztabelle leer? Werden die Daten alle nach dem Öffnen im Arbeitsspeicher gehalten und erst beim Schließen auf die Festplatte geschrieben oder was kann man tun, dass dies bei jeden neuen Datensatz geschieht?

    Ich muss hier unbedingt noch eine Verbesserung erreichen. Solange ich selbst mit dem Programm arbeite weiß ich, was zu tun ist, um die Daten zu retten. Aber wenn es meinen Vereinskollegen passiert ....

    Wie immer für jeden Tipp dankbar.

    Gruß Jürgen


    <--------(nur Fliegen sind schöner!)-------->

    Montag, 17. September 2018 16:38
  • Hallo Jürgen,

    wenn ich das richtig verstehe, tritt das Problem auf einem 10 Jahre alten Notebook trotz USV auf. ich persönlich würde den  schnellstens entsorgen. Ob Platte / Controller / Ram oder was auch immer defekt sind, ich sehe das angesichts des Alters als wirtschaflichen Totalschaden.

    Dein Ärger oder der deiner Vereinkollegen steht m.E. nach in keinem Verhältnis zum Kaufpreis eines einfachen Office-Notebooks (ab 300,-)

    Noch eine Anmerkung zum Cursor :

    Du kannst mit select .. order by feldy into cursor xxx eine Reihenfolge erzwingen. Und auch ein Cursor lässt sich wie eine Tabelle mit Index On indizieren.

    Bei deinem Programm sehe ich allerdings keinen großen Unterschied ob Du einen Cursor "verkauf" erstellst und befüllst oder eine Tabelle verkauf vor jedem neuen Vorgang zappst. Der Vorteil des Cursors ist eine garantiert frische Datei ohne Abhängigkeiten vom Zap, ähnlich einem Create Table vor jedem neuen Vorhang.

    Vielleicht würde es die Sicherheit (etwas) erhöhen wenn du die betreffenden Tabellen nur bei den entsprechenden Vorgängen kurz öffnest und wieder schliesst.

    Aber all das bringt nichts auf nicht korrekt funktionierender Hardware.

    Grüße aus dem Norden

    Tom

    (Hardware ist in Silizium gegossene Heimtücke)

    Dienstag, 18. September 2018 06:59
  • Hallo Jürgen,

    wenn ich das richtig verstehe, tritt das Problem auf einem 10 Jahre alten Notebook trotz USV auf. ich persönlich würde den  schnellstens entsorgen. Ob Platte / Controller / Ram oder was auch immer defekt sind, ich sehe das angesichts des Alters als wirtschaflichen Totalschaden.

    Dein Ärger oder der deiner Vereinkollegen steht m.E. nach in keinem Verhältnis zum Kaufpreis eines einfachen Office-Notebooks (ab 300,-)

    Noch eine Anmerkung zum Cursor :

    Du kannst mit select .. order by feldy into cursor xxx eine Reihenfolge erzwingen. Und auch ein Cursor lässt sich wie eine Tabelle mit Index On indizieren.

    Bei deinem Programm sehe ich allerdings keinen großen Unterschied ob Du einen Cursor "verkauf" erstellst und befüllst oder eine Tabelle verkauf vor jedem neuen Vorgang zappst. Der Vorteil des Cursors ist eine garantiert frische Datei ohne Abhängigkeiten vom Zap, ähnlich einem Create Table vor jedem neuen Vorhang.

    Vielleicht würde es die Sicherheit (etwas) erhöhen wenn du die betreffenden Tabellen nur bei den entsprechenden Vorgängen kurz öffnest und wieder schliesst.

    Aber all das bringt nichts auf nicht korrekt funktionierender Hardware.

    Grüße aus dem Norden

    Tom

    (Hardware ist in Silizium gegossene Heimtücke)

    Ja, das mit Hardware ist klar. Da hast Du schon recht.

    Es gibt natürlich immer wieder mal "Spinner", die einem das Leben schwer machen. Der PC wird einfach mal ausgeschaltet, ohne das Programm zu beenden, nach dem Motto: mal sehen, was dann passiert.

    Trotzdem ist mir noch nicht klar, warum die Umsatztabelle dann geleert ist. Dazu kenne ich VFP intern zu wenig.

    Aber egal. Ich werde die Anzahl der Sicherungsdateien auf drei Generationen erweitern und nach und nach die beiden Tbellen, die dann immer zerstört werden (seltsamerweise immer dieselben von 8) nur bei Bedarf öffnen und danach gleich wieder schließen. Mal sehen, was dann bei einem Programmabsturz (gewollt oder ungewollt) passiert.

    Danke für Deine Hilfe und Anregungen.

    Gruß aus dem Bundesligadorf Hoffenheim

    Jürgen


    <--------(nur Fliegen sind schöner!)-------->

    Freitag, 21. September 2018 09:24
  • Ohne das im Detail gelesen zu haben reagiere ich jetzt hier erst mal auf die Screenshots. Die Fehlermeldung betrifft die Formulare SCX, in Datensatz Nummer 15 wird vermutlich ein Datensatz der Datenumgebung sein, der weiderum mit einer DBF zu tun haben könnte.  

    Das SCX selbst wird eingebettet in die EXE sich nicht geändert haben, insofern ist nicht zu vermuten, dass das SCX defekt ist, aber genaueres kriegt man dennoch darüber heraus, dass man das SCX mal aufmacht und schaut was da in Datensatz 15 genau drin steht.

    Wie ich sehe, setzt Du kein eigenes Errorhandling ein und kriegst so nur die Fehlemeldung selbst ohne Info über Ort und Zeilennummer oder sonstge Nebeninfoo, z-B- Welches Formular.

    Hier findest Du Code, den Du einsetzen kannst, das gehört zu den Essetnials jeder Anwendung: http://doughennig.com/Papers/Pub/errorh.pdf

    Tschüß, Olaf.

    Samstag, 3. November 2018 16:39
  • Hallo Olaf,

    vielen Dank für die Informationen und die Zusendung des Links. Ich habe mir das 24seitige Dokument ausgedruckt und werde es studieren.

    Momentag habe ich bei unserem Bonkassenprogramm keinen Zeitdruck, da die nächste Veranstaltung erst nächstes Jahr stattfindet. Außerdem ist das Wertter zurzeit zu schön, um am PC zu sitzen. Das hebe ich mir für die Herbsstürme auf. Ich werde mich wieder melden und dann berichten ...

    Schönen Sonntag und viele Grüße

    Jürgen


    <--------(nur Fliegen sind schöner!)-------->

    Samstag, 3. November 2018 17:51