Question

Le programme principal est donc en C#.Insertion de nouveaux enregistrements dans une table de base de données VFP.La génération du prochain identifiant de l'enregistrement via

select max(id)+1 from table

, j'ai donc mis ce code dans une DLL de compilation dans VFP et j'appelle cet objet COM via C#.

L'objet COM renvoie le nouvel ID dans environ 250 ms.Je fais ensuite simplement une mise à jour via OLEDB.Le problème que j'ai est qu'une fois que l'objet COM a renvoyé l'ID nouvellement inséré, je ne peux pas le trouver immédiatement à partir de C# via OLEDB.

select id form  table where id = *newlyReturnedID*

renvoie 0 lignes en arrière.Si j'attends une période inconnue, la requête renverra 1 ligne.Je ne peux que supposer qu'il renvoie 0 ligne immédiatement car il n'a pas encore ajouté l'ID nouvellement créé dans l'index et donc la sélection ne peut pas le trouver.

Quelqu'un d'autre a-t-il déjà rencontré quelque chose de similaire ?Si oui, comment l’avez-vous géré ?

DD

Était-ce utile?

La solution

Avertissement:votre code est défectueux dans un environnement multi-utilisateurs.Deux personnes pourraient exécuter la requête en même temps et obtenir le même identifiant.L'un d'eux échouera lors de l'INSERT si la colonne possède une clé primaire ou candidate, ce qui constitue une bonne pratique pour les champs clés.

Ma recommandation est soit que l'ID soit un champ entier à incrémentation automatique (je n'en suis pas fan), soit, mieux encore, de créer une table de clés.Chaque enregistrement de la table concerne une table à laquelle des clés sont attribuées.J'utilise une 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 le suivant :

FONCTION NextCounter(tcAlias)

LOCAL lcAlias, ;lnValeurNext, ;lnOldReprocess, ;lnOldArea

lnOldArea = SELECT()

SI PARAMETERS() < 1 lcAlias = ALIAS()

SI CURSORGETPROP(« SOURCETYPE ») = DB_SRCLOCALVIEW *-- Tentative d’obtenir la table de base lcAlias = LOWER(CURSORGETPROP(« TABLES »)) lcAlias = SUBSTR(lcAlias, AT(« ! », lcAlias) + 1) ENDIF AUTRE lcAlias = LOWER(tcAlias) ENDIF

lnOrderNumber = 0 lnAncienRetraitement = SET('REPROCESS')

*-- Verrouiller jusqu’à ce que l’utilisateur appuie sur Échap DÉFINIR LE RETRAITEMENT SUR AUTOMATIQUE

SI! USED(« contre-générateur ») USE EventManagement !countergenerator IN 0 SHARED ALIAS countergenerator ENDIF

Contre-générateur SELECT

IF SEEK(LOWER(lcAlias), « countergenerator », « ckey ») SI RLOCK() lnNextValue = contregénérateur.iValue REMPLACER le contregénérateur.iValue PAR le compteur générateur.iValue + 1 OUVRIR ENDIF AUTRE * Créez le nouvel enregistrement avec la valeur de départ.AJOUTER UN ESPACE VIDE DANS le compteur MÉMO MEMVAR DISPERSÉ m.cClé = LOWER(lcAlias) m.iValue = 1 m.mNote = « Créé automatiquement par procédure stockée. » m.tMis à jour = DATETIME() RASSEMBLER LE MÉMO MEMVAR

SI RLOCK() lnNextValue = contregénérateur.iValue REMPLACER le contregénérateur.iValue PAR le compteur générateur.iValue + 1 OUVRIR ENDIF ENDIF

SÉLECTIONNER (lnAncienZone) DÉFINIR RETRAITEMENT SUR lnOldReprocess

RETURN lnValeurSuivante ENDFUNC

Le RLOCK() garantit qu'il n'y a pas de conflit pour les enregistrements et est suffisamment rapide pour ne pas gêner le processus.C'est bien plus sûr que l'approche que vous adoptez actuellement.

Rick Schummer
MVP VFP

Autres conseils

VFP doit VIDER ses WorkAreas .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top