Avertissement: votre code est défectueux dans un environnement multi-utilisateur. Deux personnes peuvent exécuter la requête en même temps et obtenir le même ID. L'un d'eux échouera sur l'INSERT si la colonne a une clé primaire ou candidate, ce qui est une bonne pratique pour les champs clés.
Ma recommandation est soit d'avoir l'ID soit un champ entier auto-incrémentant (je ne suis pas un fan d'entre eux), ou mieux encore, créer une table de clés. Chaque enregistrement dans la table est pour une table qui obtient des clés assignées. J'utilise la structure similaire à celle-ci:
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
Maintenant, le code de la procédure stockée dans le DBC (ou dans un autre programme) est la suivante:
FONCTION NextCounter (tcAlias)
LOCAL lcAlias,; lnNextValue,; lnOldReprocess,; lnOldArea
lnOldArea = SELECT()
SI PARAMETRES() lcAlias = ALIAS()
IF CURSORGETPROP ("SourceType") = DB_SRCLOCALVIEW * - Tentative d'obtenir la table de base lcAlias = inférieur (CURSORGETPROP ("Tableaux")) lcAlias = substr (lcAlias, AT ("!", lcAlias) + 1) ENDIF AUTRE lcAlias = BAS (tcAlias) ENDIF
lnOrderNumber = 0 lnOldReprocess = SET ('RETRAITER')
* - presse verrouillage jusqu'à ce que l'utilisateur Esc SET RETRAITER AUTOMATIQUE POUR
IF USED ("countergenerator") UTILISATION eventmanagement!countergenerator IN 0 SHARED ALIAS countergenerator ENDIF
SELECT countergenerator
IF SEEK (inférieur (lcAlias), "countergenerator", "touche c") IF RLOCK() = lnNextValue countergenerator.iValue REMPLACER countergenerator.iValue WITH countergenerator.iValue + 1 UNLOCK ENDIF ELSE * Créez le nouvel enregistrement avec la valeur de départ. CONTEND BLANK IN contre-générateur MEMOIRE MEMOIRE SCATTER m.cKey = LOWER (lcAlias) m.iValue = 1 m.mNote = "Créé automatiquement par la procédure stockée". m.tUpdated = DATETIME() GATHER MEMVAR MEMO
IF RLOCK() = lnNextValue countergenerator.iValue REMPLACER AVEC countergenerator.iValue countergenerator.iValue + 1 UNLOCK ENDIF ENDIF
SELECT (lnOldArea) SET POUR RETRAITER lnOldReprocess
RETOUR lnNextValue ENDFUNC
Le RLOCK() s'assure qu'il n'y a pas de conflit pour les enregistrements et est assez rapide pour ne pas geler le processus. C'est beaucoup plus sûr que l'approche que vous prenez actuellement.
Rick Schummer
VFP MVP