2

私は現在、ユーザーがそのテーブルの1つのスキーマの一部を指定できるようにするレガシーシステムを更新しています。ユーザーは、このインターフェースを介してテーブルの列を作成および削除できます。このレガシーシステムはADO2.8を使用しており、データベースとしてSQL Server 2005を使用しています(この獣を近代化する試みが始まる前に、どのデータベースを使用していたかを知りたくありません...しかし、私は逸脱します。=))

この同じ編集プロセスで、ユーザーは、これらのユーザー作成フィールドに格納できる有効な値のリストを定義(および変更)できます(ユーザーがフィールドに入力できる値を制限したい場合)。

ユーザーがフィールドの有効なエントリのリストを変更したときに、有効な値の1つを削除すると、新しい「有効な値」を選択して、この(現在は無効な)値を含む行をマップできます。それらは再び有効な値を持ちます。

古いコードを調べてみると、上記の変更はトランザクション内で行われないため、システムが無効な状態になることに対して非常に脆弱であることがわかりました(したがって、他の誰かが上記のプロセスの途中でやって来て、独自の変更...まあ、あなたは引き起こすかもしれない問題を想像することができます)。

問題は、単一のトランザクションでそれらを更新しようとしていることですが、コードがそのテーブルのスキーマを変更する部分に到達するたびに、他のすべての変更(行の値の更新、スキーマが変更されたかどうかに関係なく、トランザクションのその時点までに作成されたテーブルは完全に無関係なテーブルである可能性があります)サイレントにドロップされているように見えます。ドロップされたことを示すエラーメッセージは表示されず、最後にトランザクションをコミットしてもエラーは発生しません...しかし、トランザクションで更新されるはずのテーブルを調べると、新しい列のみが表示されますある。行われたスキーマ以外の変更は保存されません。

ネットで答えを探すのは、これまでのところ、数時間の無駄であることがわかっています...そこで私は助けを求めてここに向かいます。テーブルのスキーマを更新し、テーブル内の行を更新する(同じテーブルであろうと他のテーブルであろうと)ADOを介してトランザクションを実行しようとした人はいますか?許可されていませんか?この状況で役立つ可能性のあるドキュメントはありますか?

編集:

さて、私はトレースを行い、これらのコマンドはデータベースに送信されました(括弧内の説明)

(ここで何が起こっているのかわかりません。一時的なストアドプロシージャを作成しているようです...?)


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トレースにありませんでした。

4

2 に答える 2

1

コードはサーバー側のカーソルを使用しています。それがこれらの呼び出しの目的です。呼び出しの最初のセットは、カーソルの準備/オープンです。次に、カーソルから行をフェッチします。最後にカーソルを閉じます。これらの sproc は、OPEN CURSOR、FETCH NEXT、CLOSE CURSOR T-SQL ステートメントに似ています。

もっと詳しく調べる必要がありますが (後で調べます)、サーバー側カーソル、カプセル化トランザクション、および DDL で何かが起こっていると思います。

いくつかの質問:

  1. この場合、サーバー側のカーソルを使用するつもりですか?
  2. ADO コマンドはすべて同じアクティブな接続を使用していますか?

アップデート:

何が起こっているのか正確にはわかりません。

サーバー側カーソルを使用しているように見えるので、生成された SQL ステートメントを実行してスキーマを変更し、動的テーブル内のデータを更新するだけでなく、Recordset.Update() を使用して変更をサーバーにプッシュできます。明示的なトランザクション内で、同じ接続を使用します。

カーソル操作が残りのトランザクションにどのような影響を与えるか、またはその逆の影響があるかどうかはわかりません。正直言って、これが機能していないことに驚いています。

どの程度の変更になるかはわかりませんが、サーバー側のカーソルから離れて、テーブルの更新用に UPDATE ステートメントを作成することをお勧めします。

申し訳ありませんが、これ以上お役に立てませんでした。

ところで- sp_cursor 呼び出しに関する次の情報を見つけました。

http://jtds.sourceforge.net/apiCursors.html

于 2008-09-12T02:26:27.287 に答える
0

あなたが説明する振る舞いは許可されています。スキーマを変更するコードはどのようになっていますか?その場でSQLを構築し、ADOコマンドを使用して実行しますか?またはADOXを使用していますか?

データベースサーバーにアクセスできる場合は、概説したシナリオをテストしながらSQLプロファイラートレースを実行してみてください。トレースがエラー/ロールバックをログに記録するかどうかを確認します。

于 2008-09-11T23:38:42.633 に答える