В настоящее время я обновляю устаревшую систему, которая позволяет пользователям определять часть схемы одной из ее таблиц. Пользователи могут создавать и удалять столбцы из таблицы через этот интерфейс. Эта устаревшая система использует ADO 2.8 и использует SQL Server 2005 в качестве своей базы данных (вы даже не хотите знать, какую базу данных она использовала до того, как началась попытка модернизации этого зверя ... но я отвлекся. =))
В этом же процессе редактирования пользователи могут определить (и изменить) список допустимых значений, которые могут быть сохранены в этих пользовательских полях (если пользователь хочет ограничить то, что может быть в поле).
Когда пользователь изменяет список допустимых записей для поля, если он удаляет одно из допустимых значений, ему разрешается выбрать новое «допустимое значение» для сопоставления любых строк, имеющих это (теперь недействительное) значение в нем. , так что теперь они снова имеют действительное значение.
Просматривая старый код, я заметил, что он чрезвычайно уязвим для перевода системы в недопустимое состояние, поскольку упомянутые выше изменения не вносятся в транзакцию (поэтому, если кто-то еще прошел половину процесса, упомянутого выше) и внесли свои изменения ... ну, вы можете себе представить проблемы, которые могут вызвать).
Проблема в том, что я пытался заставить их обновляться в рамках одной транзакции, но всякий раз, когда код попадает в ту часть, где он меняет схему этой таблицы, все остальные изменения (обновление значений в строках, будь то в таблице, где схема изменилась или нет ... они могут быть даже совершенно не связанными таблицами), составленными до этого момента в транзакции, по-видимому, незаметно отброшены. Я не получаю сообщение об ошибке, указывающее, что они были отброшены, и когда я фиксирую транзакцию в конце, ошибка не возникает ... но когда я иду, чтобы посмотреть таблицы, которые должны были быть обновлены в транзакции, только новые столбцы здесь. Ни одно из внесенных изменений, не внесенных в схему, не сохраняется.
Пока что поиск ответов в сети оказался пустой тратой пары часов ... поэтому я обращаюсь за помощью. Кто-нибудь когда-нибудь пытался выполнить транзакцию через ADO, которая одновременно обновляет схему таблицы и обновляет строки в таблицах (будь то та же таблица или другие)? Разве это не разрешено? Есть ли какая-либо документация, которая могла бы помочь в этой ситуации?
EDIT:
Хорошо, я сделал трассировку, и эти команды были отправлены в базу данных (пояснения в скобках)
(я не знаю, что здесь происходит, похоже, он создает временную хранимую процедуру ...?)
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 не было сообщений о том, что во время транзакции что-то пошло не так.