- - PR -
ADOからストアドへパラメータを渡す時にエラー
1
| 投稿者 | 投稿内容 | ||||
|---|---|---|---|---|---|
|
投稿日時: 2006-06-30 15:27
初めての投稿です。宜しくお願いします。
ADOからストアドへパラメータを渡したいのですが、実行時エラー3265「要求された名前、または序数に対応する項目がコレクションで見つかりません」が出てしまいます。 トランザクション開始後、ストアドAを実行し、次にストアドBを実行しようとすると上記のエラーが発生します。 トランザクション処理を省けば解消されるのですが、省かずに解決する方法がわかりません。 また、.Parameters.Countをチェックしてみると「0」が返ってきます。 何をどうすればいいのでしょうか? ADO側 -------- 'トランザクション開始 saCn.BeginTrans 'ストアドA実行 With cmd .CommandText = "usp_Search_Kouho" .CommandType = adCmdStoredProc .Parameters.Refresh .Parameters(1) = frm!cmb_OLDCD <--問題なし End With Set rst = cmd.Execute If cmd.Parameters("@ERR").Value <> 0 Then rst.Close: Set rst = Nothing GoTo UspErr End If 'ストアドB実行 With cmd .CommandText = "usp_Search_Universe" .CommandType = adCmdStoredProc .Parameters.Refresh .Parameters(1) = frm!cmb_OLDCD <--ここでエラー End With Set rs = cmd.Execute If cmd.Parameters("@ERR").Value <> 0 Then rst.Close: Set rst = Nothing GoTo UspErr End If 以下、処理が続く ストアドB ---------- Alter PROCEDURE usp_Search_Universe @OLDCD varchar(4), @ERR int OUTPUT AS SELECT TOUROKU,ANALYSTCODE,ANALYST FROM T_Universe WHERE OLDCD = @OLDCD IF @@ERROR<>0 SET @ERR = @@ERROR | ||||
|
投稿日時: 2006-06-30 18:18
perche さん、こんにちは。
.Parameters.Append([object]) ではないのでしょうか? 私としましては、むしろ 「ストアド プロシージャ A」 が問題ないのが謎です。 _________________ C# と VB.NET の入門サイト じゃんぬねっと日誌 | ||||
|
投稿日時: 2006-07-01 00:26
お疲れ様です。 TimberLandChapel です。 パラメーターの作成と Refresh の問題ではなく, 単に ADO でのトランザクションの使用法に関する問題です。 以下のソースで試してもらうとわかりやすいのですが, 「手動または分散トランザクション モードのため、新規接続を作成できません。」 というエラーが発生するはずです。 ADO だと仕様だと思うんですが, 2重に SELECT 接続を開けません。 perche さんのストアドの名称からして,選択を行うクエリですよね? そもそも,トランザクション内で, 更新を伴わないデータの取得を行う必要性はないはずです。 ロックとの要件を整理して, 「トランザクションの最短化」を行ってください。 ■改善方法 半分以上はリファクタリングの話になりますが, 1.コマンドオブジェクトの使い回しはしない 2.トランザクション内では純粋にデータの変更のみを送信する 3.トランザクション外ですべての更新に必要な情報を整えておく という風にコードを改善してください。 ↓多少書いています。 http://timberlandchapel.com/adotips.html [CODE]----- Private Sub Test() On Error GoTo Catch Dim connection As New ADODB.connection connection.ConnectionString = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=Test;Data Source=METATRON\SANDALPHON;" Dim command As New ADODB.command Dim secondCommand As New ADODB.command Dim recordSet As New ADODB.recordSet connection.Open connection.BeginTrans With command .ActiveConnection = connection .CommandText = "usp_Test1" .CommandType = adCmdStoredProc .Parameters.Refresh .Parameters(1) = 1 End With With secondCommand .ActiveConnection = connection .CommandText = "usp_Test2" .CommandType = adCmdStoredProc .Parameters.Refresh .Parameters(1) = 1 End With Set recordSet = command.Execute If command.Parameters("@ERR").Value <> 0 Then Err.Raise vbObjectError + 1001 End If Set recordSet = secondCommand.Execute If command.Parameters("@ERR").Value <> 0 Then Err.Raise vbObjectError + 1002 End If connection.CommitTrans Finally: If Not recordSet Is Nothing Then If recordSet.State <> adStateClosed Then recordSet.Close Set recordSet = Nothing End If If Not command Is Nothing Then Set command = Nothing End If If Not secondCommand Is Nothing Then Set secondCommand = Nothing End If If Not connection Is Nothing Then If connection.State <> adStateClosed Then connection.Close Set connection = Nothing End If Exit Sub Catch: connection.RollbackTrans GoTo Finally End Sub [CODE]----- ---------- TimberLandChapel http://blogs.timberlandchapel.com/blogs/timberlandchapel/ | ||||
|
投稿日時: 2006-07-03 11:39
レスありがとうございます。返答が遅くなりました。
お二人の回答を拝見する前に、カーソルの問題なのではという記述を見つけ、 saCn.CursorLocation = adUseClient Set cmd.ActiveConnection = saCn とすることで、一応解決はしました。 ただ、TLCさんのアドバイスにあるようなことには沿っていませんよね。 トランザクションは初めてまともに取り組んでいるところで、右往左往しているのが 現状です。とても難しく感じています。 TLCさんからのアドバイスを元にトランザクションを開始する位置を変更してみたのですが、 同様のエラーとなってしまいました。 実際のコードは、「以下、処理が続く」とあるようにもっと長いものです。 ストアドAとBは確かに更新系のものではないので、トランザクション外としました。 次に更新系のストアドCを実行するので、この直前でトランザクションを開始するように したのですが、ここでエラーとなりました。 以下はストアドCの内容です。 DELETEする前にSELECT COUNT(*)〜等があるからエラーとなるのでしょうか? もう少しお付き合い願えたらと思います。 Alter PROCEDURE usp_MK_Zenkai_Data @ERR int OUTPUT AS SET @ERR = @@ERROR IF @ERR=0 BEGIN --テーブルの初期化 IF (SELECT COUNT(*) FROM WT_Zenkai_Data)>0 BEGIN DELETE FROM WT_Zenkai_Data --エラー値を取得 SET @ERR = @@ERROR END END IF @ERR=0 BEGIN --実績データと予想データをひとつのテーブルに挿入する INSERT INTO WT_Zenkai_Data SELECT * FROM v_Zenkai_Data --エラー値を取得 SET @ERR = @@ERROR END IF @ERR<>0 PRINT 'エラーが発生しました: エラー番号' + CONVERT(CHAR,@ERR) | ||||
|
投稿日時: 2006-07-05 13:00
お疲れ様です。 TimberLandChapel です。 設計のスタイルの違いが大きく出ていますので,なかなか難しいところだとは思うのですが (さらにそのスタイル自体にも賛否両論ありますから) 直近では, EXISTS を使用することで,結果セットを返さないデータの存在判定を行うことで, 一部解決できると思います。 さて,ここからは議論になるところだと思いますが, トランザクションで行う更新は, その更新が実行される前の状態のみに依存するはずです。 これは,トランザクションの原子性を確保するために非常に重要です。 とすると, その UPDATE 文を発行するべきか否かという判断は, トランザクション開始前にすべてとることができるということになります。 なので,自分は ■トランザクション用のコマンドを組み立てる前に ■すべての必要な判定条件をローカル側にキャッシュする ■必要な更新を同時実行制御をかけながらトランザクション化する とします。 このためには,やはりCRUIDレベルからどこで何が判定され,更新されるべきなのかを チューニングすることになると思います。 ---------- TimberLandChapel http://blogs.timberlandchapel.com/blogs/timberlandchapel/ | ||||
|
投稿日時: 2006-07-06 09:27
TLCさん、レスありがとうございます。
いろいろ試行錯誤した結果、下記のような方法に落ち着きました。 1)ストアドAとBは存在確認のみなので、ストアドを使わずレコードセットを作成 2)ストアドCの直前でトランザクションを開始する 3)ロックをかけることで対処できる部分は、トランザクション外へ出しました。 これでエラーが出ることもなく、実行できるようになりました。 その他、TLCさんのアドバイス通り、ストアド実行前に条件判断を行うように心がけました。 時間的な制約もあり、全面見直しというわけにはいきませんでしたが、それでも当初の記述 と比べると大分短時間でのトランザクションで済むようになったと思います。 トランザクションとロックがどうもごちゃごちゃになってしまって、余計に混乱したようです。 結果、何でもトランザクションの中にいれこんでしまうような形になっていたりしました。 その辺りも自分なりに整理してみました。 お時間さいていただき、ありがとうございました。 今後ともよろしくお願い致します。 | ||||
1
