Warnung: Ihr Code ist in einer Mehrbenutzerumgebung fehlerhaft. Zwei Personen können die Abfrage zur gleichen Zeit ausführen und die gleiche ID erhalten. Einer von ihnen wird auf dem INSERT fehlschlagen, wenn die Spalte einen Primär- oder einen Kandidatenschlüssel hat, was eine Best Practice für Schlüsselfelder ist.
Meine Empfehlung ist, entweder die ID ein automatisch inkrementieren Integer-Feld (ich bin kein Fan von ihnen), oder noch besser, erstellen Sie eine Tabelle von Schlüsseln. Jeder Datensatz in der Tabelle bezieht sich auf eine Tabelle, die Schlüssel zugewiesen bekommt. Ich benutze die eine ähnliche Struktur wie diese an:
Structure for: countergenerator.dbf
Database Name: conferencereg.dbc
Long table name: countergenerator
Number of records: 0
Last updated: 11/08/2008
Memo file block size: 64
Code Page: 1252
Table Type: Visual FoxPro Table
Field Name Type Size Nulls Next Step Default
----------------------------------------------------------------------------------------------------------------
1 ccountergenerator_pk Character 36 N guid(36)
2 ckey Character (Binary) 50 Y
3 ivalue Integer 4 Y
4 mnote Memo 4 Y "Automatically created"
5 cuserid Character 30 Y
6 tupdated DateTime 8 Y DATETIME()
Index Tags:
1. Tag Name: PRIMARY
- Type: primary
- Key Expression: ccountergenerator_pk
- Filter: (nothing)
- Order: ascending
- Collate Sequence: machine
2. Tag Name: CKEY
- Type: regular
- Key Expression: lower(ckey)
- Filter: (nothing)
- Order: ascending
- Collate Sequence: machine
Jetzt ist der Code für die gespeicherte Prozedur in der DBC (oder in einem anderen Programm) ist dies:
FUNCTION NextCounter (tcAlias)
LOCAL lcAlias,; lnNextValue,; lnOldReprozess,; lnOldArea
lnOldArea = SELECT()
IF PARAMETERS() lcAlias = ALIAS()
IF CURSORGETPROP ("SOURCE") = DB_SRCLOCALVIEW * - Versuch Basistabelle zu erhalten lcAlias = LOWER (CURSORGETPROP ("TABLES")) lcAlias = SUBSTR (lcAlias, AT ("!", lcAlias) + 1) ENDIF ELSE lcAlias = LOWER (tcAlias) ENDIF
lnOrderNumber = 0 lnOldReprocess = SET ('REPROCESS')
* - sperren, bis der Benutzer drückt Esc SET REPROCESS auf AUTOMATIC
IF USED ("countergenerator") USE Eventmanagement!countergenerator IN 0 SHARED ALIAS countergenerator ENDIF
SELECT countergenerator
IF Seek (LOWER (lcAlias), "countergenerator", "ckey") IF RLOCK() = lnNextValue countergenerator.iValue countergenerator.iValue REPLACE WITH countergenerator.iValue + 1 UNLOCK ENDIF ELSE * Erstellen Sie den neuen Datensatz mit dem Startwert. APPEND BLANK IN Gegengenerator SCATTER MEMVAR MEMO m.cKey = UNTERE (lcAlias) m.iValue = 1 m.mNote = "Automatisch von gespeicherten Prozedur erstellt." m.tUpdated = DATETIME-() GATHER MEMVAR MEMO
IF RLOCK() = lnNextValue countergenerator.iValue REPLACE countergenerator.iValue MIT countergenerator.iValue + 1 UNLOCK ENDIF ENDIF
SELECT (lnOldArea) SET REPROCESS TO
RETURN lnNextValue ENDFUNC
lnOldReprocess
Das RLOCK() stellt sicher, dass es keine Konflikte für die Datensätze gibt, und es ist schnell genug, um keinen Engpass im Prozess zu haben. Dies ist viel sicherer als die aktuelle Vorgehensweise.
Rick Schummer
VFP MVP