Вопрос

Итак, основная программа написана на C #.Вставка новых записей в таблицу базы данных VFP.Потребовалось слишком много времени, чтобы сгенерировать следующий идентификатор для записи через

select max(id)+1 from table

, поэтому я поместил этот код в библиотеку DLL для компиляции в VFP и вызываю этот COM-объект через C #.

COM-объект возвращает новый идентификатор примерно через 250 мс.Затем я просто выполняю обновление через OLEDB.Проблема, с которой я сталкиваюсь, заключается в том, что после того, как COM-объект возвращает вновь вставленный идентификатор, я не могу сразу найти его из C # через OLEDB

select id form  table where id = *newlyReturnedID*

возвращает 0 строк назад.Если я подожду неизвестный период времени, запрос вернет 1 строку.Я могу только предположить, что он немедленно возвращает 0 строк, потому что ему еще предстоит добавить новоиспеченный идентификатор в индекс, и поэтому select не может его найти.

Кто-нибудь еще когда-нибудь сталкивался с чем-то подобным?Если да, то как вы с этим справились?

ДД

Это было полезно?

Решение

Предупреждение:ваш код имеет недостатки в многопользовательской среде.Два человека могли бы выполнить запрос одновременно и получить один и тот же идентификатор.Один из них завершится ошибкой при ВСТАВКЕ, если столбец имеет первичный или потенциальный ключ, что является наилучшей практикой для ключевых полей.

Моя рекомендация состоит в том, чтобы либо сделать ID автоматически увеличивающимся целочисленным полем (я не их поклонник), либо, что еще лучше, создать таблицу ключей.Каждая запись в таблице предназначена для таблицы, которой назначаются ключи.Я использую структуру, похожую на эту:

       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

Теперь код для хранимой процедуры в DBC (или в другой программе) выглядит следующим образом:

ФУНКЦИЯ NextCounter (tcAlias)

МЕСТНЫЕ КАЛИИ, ;lnNextValue, ;Процесс lnOldReprocess, ;Область действия

lnOldArea = ВЫБРАТЬ()

IF ПАРАМЕТРЫ() < 1 lcAlias = ПСЕВДОНИМ()

IF CURSORGETPROP("SOURCETYPE") = DB_SRCLOCALVIEW *-- Попытка получить базовую таблицу lcAlias = НИЖНИЙ(CURSORGETPROP("ТАБЛИЦЫ")) lcAlias = НИЖНИЙ(lcAlias, AT("!", lcAlias) + 1) КОНЕЧНЫЙ ещё lcAlias = НИЖНИЙ (tcAlias) КОНЕЧНЫЙ

lnOrderNumber = 0 lnOldReprocess = УСТАНОВИТЬ ('ПОВТОРНО ОБРАБОТАТЬ')

*-- Блокировка до тех пор, пока пользователь не нажмет клавишу Esc УСТАНОВИТЕ АВТОМАТИЧЕСКИЙ РЕЖИМ ПОВТОРНОЙ ОБРАБОТКИ

IF !ИСПОЛЬЗУЕТСЯ("countergenerator") ИСПОЛЬЗУЙТЕ EventManagement!countergenerator В 0 С ОБЩИМ ПСЕВДОНИМОМ countergenerator ENDIF

ВЫБЕРИТЕ контргенератор

IF SEEK(НИЖНИЙ (lcAlias), "контргенератор", "ckey") IF RLOCK() lnNextValue = контргенератор.IValue ЗАМЕНИТЕ контргенератор.IValue На countergenerator.IValue + 1 РАЗБЛОКИРОВАТЬ ENDIF ещё * Создайте новую запись с начальным значением.ДОБАВИТЬ ПРОБЕЛ В countergenerator РАЗБРОС MEMVAR MEMO m.cKey = НИЖНИЙ (lcAlias) m.IValue = 1 m.mNote = "Автоматически создается хранимой процедурой". m.tUpdated = DATETIME() СОБЕРИТЕ MEMVAR MEMO

IF RLOCK() lnNextValue = счетчик-генератор.IValue ЗАМЕНИТЕ счетчик-генератор.IValue НА countergenerator.IValue + 1 РАЗБЛОКИРУЙТЕ КОНЕЦ КОНЕЦ

SELECT (lnOldArea) УСТАНОВИТЕ ДЛЯ ПАРАМЕТРА REPROCESS ЗНАЧЕНИЕ lnOldReprocess

ВОЗВРАЩАЕТ значение lnNextValue ENDFUNC

RLOCK() гарантирует отсутствие конкуренции за записи и работает достаточно быстро, чтобы не создавать узких мест в процессе.Это намного безопаснее, чем подход, который вы используете в настоящее время.

Рик Шуммер
VFP MVP

Другие советы

ВФП необходимо РУМЯНЕЦ его рабочие зоны.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top