我目前正在更新一个遗留系统,该系统允许用户指定其中一个表的部分架构。用户可以通过此界面在表中创建和删除列。这个遗留系统使用 ADO 2.8,并使用 SQL Server 2005 作为其数据库(在尝试对这头野兽进行现代化改造之前,您甚至不想知道它使用的是什么数据库……但我离题了。=))
在同一编辑过程中,用户可以定义(和更改)可以存储在这些用户创建的字段中的有效值列表(如果用户想要限制字段中可以包含的内容)。
当用户更改字段的有效条目列表时,如果他们删除了其中一个有效值,则允许他们选择一个新的“有效值”来映射其中包含此(现在无效)值的任何行,以便它们现在再次具有有效值。
在查看旧代码时,我注意到它极易使系统进入无效状态,因为上述更改不是在事务中完成的(因此,如果其他人在上述过程的中途出现并进行了他们的自己的变化......好吧,你可以想象可能导致的问题)。
问题是,我一直试图让它们在单个事务下更新,但是每当代码到达它更改该表架构的部分时,所有其他更改(更新行中的值,无论是在架构更改与否的表......它们甚至可以是完全不相关的表)在事务中构成的那一点似乎被静默删除。我没有收到表明它们已被删除的错误消息,并且当我最后提交事务时没有引发错误......但是当我去查看应该在事务中更新的表时,只有新列在那里。所做的任何非架构更改都不会保存。
到目前为止,在网上寻找答案被证明是浪费几个小时......所以我转向这里寻求帮助。有没有人尝试过通过 ADO 执行事务,既更新表的架构又更新表中的行(无论是同一个表还是其他表)?不允许吗?是否有任何文档可以在这种情况下有所帮助?
编辑:
好的,我做了一个trace,这些命令被发送到数据库中(括号中的解释)
(我不知道这里发生了什么,看起来它正在创建一个临时存储过程......?)
declare @p1
int set @p1=180150003 declare @p3 int
set @p3=2 declare @p4 int set @p4=4
declare @p5 int set @p5=-1
(检索包含用户生成字段的定义信息的表)
exec sp_cursoropen @p1 output,N'SELECT * FROM CustomFieldDefs ORDER BY Sequence',@p3 output,@p4 output,@p5 output select @p1, @p3, @p4, @p5
go
(我认为我的代码在这里遍历它们的列表,获取当前信息)
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,1025,1,1
go
exec sp_cursorfetch 180150003,1028,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
(这似乎是我输入定义的修改数据的地方,我遍历每个并更新自定义字段本身的定义中发生的任何更改)
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=1,@Description='asdf',@Format='U|',@IsLookUp=1,@Length=50,@Properties='U|',@Required=1,@Title='__asdf',@Type='',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=2,@Description='give',@Format='Y',@IsLookUp=0,@Length=0,@Properties='',@Required=0,@Title='_give',@Type='B',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=3,@Description='up',@Format='###-##-####',@IsLookUp=0,@Length=0,@Properties='',@Required=0,@Title='_up',@Type='N',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=4,@Description='Testy',@Format='',@IsLookUp=0,@Length=50,@Properties='',@Required=0,@Title='_Testy',@Type='',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=5,@Description='you',@Format='U|',@IsLookUp=0,@Length=250,@Properties='U|',@Required=0,@Title='_you',@Type='',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=6,@Description='never',@Format='mm/dd/yyyy',@IsLookUp=0,@Length=0,@Properties='',@Required=0,@Title='_never',@Type='D',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=7,@Description='gonna',@Format='###-###-####',@IsLookUp=0,@Length=0,@Properties='',@Required=0,@Title='_gonna',@Type='C',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
(这是我的代码在此保存开始之前通过界面删除删除的地方] ...据我所知,这也是在此事务期间实际发生的唯一事情)
ALTER TABLE CustomizableTable DROP COLUMN _weveknown;
(现在,如果任何定义被更改为需要更改用户创建的列的属性或需要添加/删除列上的索引,则在此处完成,并为任何行提供默认值给定列还没有值...请注意,据我所知,当存储过程完成时,实际上没有发生这种情况。)
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '__asdf'
go
ALTER TABLE CustomizableTable ALTER COLUMN __asdf VarChar(50) NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx___asdf') CREATE NONCLUSTERED INDEX idx___asdf ON CustomizableTable (
__asdf ASC) WITH (PAD_INDEX = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF);
go
select * from IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx___asdf') CREATE NONCLUSTERED INDEX idx___asdf ON
CustomizableTable ( __asdf ASC) WITH (PAD_INDEX = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF);
go
UPDATE CustomizableTable SET [__asdf] = '' WHERE [__asdf] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_give'
go
ALTER TABLE CustomizableTable ALTER COLUMN _give Bit NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__give') DROP INDEX idx__give ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_give] = 0 WHERE [_give] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_up'
go
ALTER TABLE CustomizableTable ALTER COLUMN _up Int NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__up') DROP INDEX idx__up ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_up] = 0 WHERE [_up] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_Testy'
go
ALTER TABLE CustomizableTable ADD _Testy VarChar(50) NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__Testy') DROP INDEX idx__Testy ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_Testy] = '' WHERE [_Testy] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_you'
go
ALTER TABLE CustomizableTable ALTER COLUMN _you VarChar(250) NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__you') DROP INDEX idx__you ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_you] = '' WHERE [_you] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_never'
go
ALTER TABLE CustomizableTable ALTER COLUMN _never DateTime NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__never') DROP INDEX idx__never ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_never] = '1/1/1900' WHERE [_never] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_gonna'
go
ALTER TABLE CustomizableTable ALTER COLUMN _gonna Money NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__gonna') DROP INDEX idx__gonna ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_gonna] = 0 WHERE [_gonna] IS NULL
go
(关闭交易...?)
exec sp_cursorclose 180150003
go
经过上面的所有这些,只发生了该列的删除。事务中它之前和之后的所有内容似乎都被忽略了,并且 SQL 跟踪中没有消息表明事务期间出现了问题。