VFP插入、索引更新
所以主程序是用C#编写的。 将新记录插入 VFP 数据库表中。 通过 生成记录的下一个 ID 花费的时间太长
select max(id)+1 from table
,因此我将该代码放入 VFP 中的编译 dll 中,并通过 C# 调用该 COM 对象。
COM 对象在大约 250 毫秒内返回新 ID。 然后我通过 OLEDB 进行更新。 我遇到的问题是,在 COM 对象返回新插入的 ID 后,我无法立即通过 OLEDB
select id form table where id = *newlyReturnedID*
返回 0 行从 C# 找到它。 如果我等待未知的时间段,查询将返回 1 行。 我只能假设它立即返回 0 行,因为它尚未将新创建的 ID 添加到索引中,因此 select 无法找到它。
还有其他人遇到过类似的事情吗? 如果是这样,你是如何处理的?
DD
So the main program is in C#. Inserting new records into a VFP database table. It was taking too long to generate the next ID for the record via
select max(id)+1 from table
, so I put that code into a compile dll in VFP and am calling that COM object through C#.
The COM object returns the new ID in about 250ms. I then just do an update through OLEDB. The problem I am having is that after the COM object returns the newly inserted ID, I cannot immediately find it from C# via the OLEDB
select id form table where id = *newlyReturnedID*
returns 0 rows back. If I wait an unknown time period the query will return 1 row. I can only assume it returns 0 rows immediately because it has yet to add the newly minted ID into the index and therefore the select cannot find it.
Has anyone else ever run into something similar? If so, how did you handle it?
DD
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
警告:您的代码在多用户环境中存在缺陷。 两个人可以同时运行查询并获得相同的 ID。 如果列具有主键或候选键,其中之一将在 INSERT 上失败,这是键字段的最佳实践。
我的建议是让 ID 成为自动递增的整数字段(我不喜欢它们),或者更好的是创建一个键表。 表中的每条记录都对应一个分配键的表。 我使用与此类似的结构:
现在 DBC(或另一个程序)中存储过程的代码是这样的:
函数 NextCounter(tcAlias)
LOCAL lcAlias, ;
lnNextValue, ;
lnOldReprocess,;
lnOldArea
lnOldArea = SELECT()
IF PARAMETERS() < 1
lcAlias = ALIAS()
IF CURSORGETPROP("SOURCETYPE") = DB_SRCLOCALVIEW
*-- 尝试获取基表
lcAlias = LOWER(CURSORGETPROP("表"))
lcAlias = SUBSTR(lcAlias, AT("!", lcAlias) + 1)
万一
别的
lcAlias = LOWER(tcAlias)
ENDIF
lnOrderNumber = 0
lnOldReprocess = SET('REPROCESS')
*-- 锁定直到用户按 Esc
将重新处理设置为自动
如果 !USED("countergenerator")
在 0 共享别名 countergenerator 中使用 EventManagement!countergenerator
ENDIF
SELECT 计数器生成器
IF SEEK(LOWER(lcAlias), "countergenerator", "ckey")
如果 RLOCK()
lnNextValue = countergenerator.iValue
将 countergenerator.iValue 替换为 countergenerator.iValue + 1
开锁
万一
别的
* 使用起始值创建新记录。
在反生成器中附加空白
分散 Memvar 备忘录
m.cKey = LOWER(lcAlias)
m.i值 = 1
m.mNote =“由存储过程自动创建。”
m.tUpdated = DATETIME()
收集 MEMVAR 备忘录
IF RLOCK()
lnNextValue = countergenerator.iValue
将 countergenerator.iValue 替换为 countergenerator.iValue + 1
开锁
万一
ENDIF
选择(lnOldArea)
将 REPROCESS 设置为 lnOldReprocess
RETURN lnNextValue
ENDFUNC
RLOCK() 确保不存在记录争用,并且速度足够快,不会造成进程瓶颈。 这比您当前采取的方法安全得多。
里克·舒默
VFP MVP
Warning: your code is flawed in a multi-user environment. Two people could run the query at the same time and get the same ID. One of them will fail on the INSERT if the column has a primary or candidate key, which is a best practice for key fields.
My recommendation is to either have the ID be a auto-incrementing integer field (I'm not a fan of them), or even better, create a table of keys. Each record in the table is for a table that gets keys assigned. I use the a structure similar to this:
Now the code for the stored procedure in the DBC (or in another program) is this:
FUNCTION NextCounter(tcAlias)
LOCAL lcAlias, ;
lnNextValue, ;
lnOldReprocess, ;
lnOldArea
lnOldArea = SELECT()
IF PARAMETERS() < 1
lcAlias = ALIAS()
IF CURSORGETPROP("SOURCETYPE") = DB_SRCLOCALVIEW
*-- Attempt to get base table
lcAlias = LOWER(CURSORGETPROP("TABLES"))
lcAlias = SUBSTR(lcAlias, AT("!", lcAlias) + 1)
ENDIF
ELSE
lcAlias = LOWER(tcAlias)
ENDIF
lnOrderNumber = 0
lnOldReprocess = SET('REPROCESS')
*-- Lock until user presses Esc
SET REPROCESS TO 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
REPLACE countergenerator.iValue WITH countergenerator.iValue + 1
UNLOCK
ENDIF
ELSE
* Create the new record with the starting value.
APPEND BLANK IN countergenerator
SCATTER MEMVAR MEMO
m.cKey = LOWER(lcAlias)
m.iValue = 1
m.mNote = "Automatically created by stored procedure."
m.tUpdated = DATETIME()
GATHER MEMVAR MEMO
IF RLOCK()
lnNextValue = countergenerator.iValue
REPLACE countergenerator.iValue WITH countergenerator.iValue + 1
UNLOCK
ENDIF
ENDIF
SELECT (lnOldArea)
SET REPROCESS TO lnOldReprocess
RETURN lnNextValue
ENDFUNC
The RLOCK() ensures there is no contention for the records and is fast enough to not have bottleneck the process. This is way safer than the approach you are currently taking.
Rick Schummer
VFP MVP
VFP 需要FLUSH 其工作区。
VFP needs to FLUSH its workareas.