- PR -

DataAdapterの自動更新機能がうまくいかない。

投稿者投稿内容
PIKU
会議室デビュー日: 2006/11/28
投稿数: 7
投稿日時: 2007-03-07 11:52
はじめまして。

現在、VisualStudio2003を使用して、件名の通りDataAdapterの自動更新を行おうと考えています。
しかし、UPDATEコマンドを発行したときに、下記エラーが発生します。
■エラー
System.InvalidOperationException: UpdateCommand の動的SQL生成は、キーである列情報を返さないSelectCommandに対してサポートされていません。

selectコマンドではキーを含む動的SQLを発行しているのにもかかわらず上記のエラーが発生します。

以下、コードの詳細です。

Dim dsTable As New DataTable
Dim dsWbsData As New DataSet
Dim dsAdapter As New OleDbDataAdapter

#Region "データセット処理"
'**********************************************************************
' [名称]
' データセット処理
' [概要]
' データグリッド内にデータをSETする。
' [引数]
' strCode   :Stringパラメータ
' strSyainCode :Stringパラメータ
' [戻り値]
' なし
' [備考]
' −
'**********************************************************************
Public Sub SetData(ByVal strCode As String, ByVal strSyainCode As String)

Dim commandBuilder As OleDbCommandBuilder
' データグリッド内のデータ初期化
dsTable.Clear()
' データセット初期化
dsWbsData.Clear()
' WHERE句初期化
strWhereLine = Nothing
' WHERE句取得
GetWhereLine(strCode, strSyainCode)
' SelectCommand初期化
dsAdapter.SelectCommand = New OleDbCommand( _
" SELECT SIRYOYM," _     ←キー項目1
& " DATASBT," _
& " DATAKNRNO_SC," _   ←キー項目2
& " DATAKNRGY_SC," _   ←キー項目3
& " D_KADOUYM, " _
& " D_JUGYOINCD," _
& " D_WBSCD, " _
& " D_SAGYOUKOUTEI," _
& " D_SAGYOUKBN," _
& " D_BUMONCD," _
& " D_KADOUYMD," _
& " D_KADOUHOUR," _
& " D_GENCCD, " _
& " D_KTDTYP," _
& " D_KOUSUKBN, " _
& " D_PRJSBT," _
& " D_WBSSBT, " _
& " D_GENCCATE," _
& " DENNO_SC," _
& " DENGY_SC," _
& " TMSTYMD," _
& " TMSTTIME" _
& " FROM NT_KADMSI " & strWhereLine _
& " ORDER BY D_JUGYOINCD, D_KADOUYMD, D_WBSCD", oConn)
' SELECT文の結果取得
' SelectCommandの結果をDataSetに設定()
dsAdapter.Fill(dsWbsData, "データ")
' データバインド
DataGrid1.SetDataBinding(dsWbsData, "データ")
End Sub
#End Region


#Region "更新ボタン押下時ハンドル処理"
'**********************************************************************
' [名称]
' 更新ボタン押下時ハンドル処理
' [概要]
' データグリッド上の更新および追加・削除されたデータをデータベースに
'  反映する。
' [引数]
' sender : ハンドルオブジェクト
' e : イベントパラメータ
' [戻り値]
' なし
' [備考]
' −
'**********************************************************************
Private Sub btnUpdate_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnUpdate.Click
Dim intCurIdx As Integer
Dim retValue As Integer
Dim sqlCB As OleDbCommandBuilder
Try
sqlCB = New OleDbCommandBuilder(dsAdapter)
' dsWbsDataが保持する情報を元に変更された個所についてDBを更新
retValue = dsAdapter.Update(dsWbsData, "当月分日報データ")
MessageBox.Show("正常にデータ更新されました。", "お知らせ")
Catch ex As Exception
'データの更新で発生したエラーを捕捉する
MessageBox.Show("データの更新に失敗しました。" _
+ vbCrLf + ex.ToString)
End Try
End Sub
#End Region
PIKU
会議室デビュー日: 2006/11/28
投稿数: 7
投稿日時: 2007-03-07 11:59
少し修正です。

#Region "更新ボタン押下時ハンドル処理"
'**********************************************************************
' [名称]
' 更新ボタン押下時ハンドル処理
' [概要]
' データグリッド上の更新および追加・削除されたデータをデータベースに
'  反映する。
' [引数]
' sender : ハンドルオブジェクト
' e : イベントパラメータ
' [戻り値]
' なし
' [備考]
' −
'**********************************************************************
Private Sub btnUpdate_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnUpdate.Click
Dim intCurIdx As Integer
Dim retValue As Integer
Dim sqlCB As OleDbCommandBuilder
Try
sqlCB = New OleDbCommandBuilder(dsAdapter)
' dsWbsDataが保持する情報を元に変更された個所についてDBを更新
retValue = dsAdapter.Update(dsWbsData, "当月分日報データ")
MessageBox.Show("正常にデータ更新されました。", "お知らせ")
Catch ex As Exception
'データの更新で発生したエラーを捕捉する
MessageBox.Show("データの更新に失敗しました。" _
+ vbCrLf + ex.ToString)
End Try
End Sub
#End Region
ぶさいくろう
ぬし
会議室デビュー日: 2005/11/22
投稿数: 1232
お住まい・勤務地: 川崎市(は俺も含めてロクな人間が住んでないよw)
投稿日時: 2007-03-07 12:14
主キーがないだけじゃないの?
PIKU
会議室デビュー日: 2006/11/28
投稿数: 7
投稿日時: 2007-03-07 15:38
返信ありがとうございます。

テーブルのキーは↑に書いた通り3つの項目について有効です。
ラフレシア
会議室デビュー日: 2006/01/30
投稿数: 7
投稿日時: 2007-03-07 15:54
DataSet上で主キーがないんですよ。
例えば、Fillの前に
dsAdapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;
を追加するとか。
PIKU
会議室デビュー日: 2006/11/28
投稿数: 7
投稿日時: 2007-03-07 16:37
返信ありがとうございます。

>dsAdapter.MissingSchemaAction = MissingSchemaAction.AddWithKey
上記のコードを追加してみましたが、やはり同じエラーが発生します。

もう少し調べてみます。
PIKU
会議室デビュー日: 2006/11/28
投稿数: 7
投稿日時: 2007-03-07 17:38
こんなヘルプを見つけました。

こいつが原因なんでしょうか?
********************************************************************************
AddWithKey 必要な列と主キー情報を追加してスキーマを完成します。主キー情報を         DataTable に追加する方法の詳細については、「FillSchema」を参照して
ください。.NET Framework OLE DB 用データ プロバイダで AddWithKey が
正しく機能するためには、ネイティブな OLE DB プロバイダが   
      DBPROP_UNIQUEROWS プロパティを設定して必要な主キー情報を取得し、
IColumnsRowset 内の DBCOLUMN_KEYCOLUMN を調べてどの列が主キー列かを確
認する必要があります。DataTable ごとに主キー制約を明示的に設定するこ
ともできます。これにより、既存のレコードと一致する入力レコードが、追
加ではなく更新されるようになります。
********************************************************************************
KI
大ベテラン
会議室デビュー日: 2007/01/10
投稿数: 239
投稿日時: 2007-03-08 19:01
原因は私もわからないのですが、調べる方向が間違ってそうなので書いておきます。

「UpdateCommand の動的SQL生成」のエラーとのことですので、
DataSet上の主キーとかは関係ないと思います。
極端な話、DataSetもDataTableも使わなくても同じエラーは出せます。
DataAdapterを生成してSelectCommandを設定して、
コマンドビルダーを生成して、そのGetUpdateCommandメソッドを呼んでみたら
同じエラーが返ってくると思います。
例えば以下のような感じで。

コード:

dsAdapter.SelectCommand = New OleDbCommand(... 略 ...)
Dim builder As New OleDbCommandBuilder(dsAdapter)
Debug.Print(dsAdapter.GetUpdateCommand().CommandText)



DataSetのUpdateのタイミングで出るのは、Updateのときに内部的に
DbCommandBuilderから更新用のコマンドを取得するからです。
要するにSELECT文に対応するUPDATE, DELETE, INSERTコマンドを
自動生成するのに失敗しているものと思われます。
その原因は、SELECT文には一意な列が含まれていないということのようです。

上記のDebug.Printのところでエラーがでないようになれば解決すると思いますので、
調査を進めるならSQL文を単一列の主キーを持つテーブルから無条件で取得するだけのSQLに書き換えてみるとか、
そういうところから始めてみてはどうでしょうか?

あと、OLEDBを使われているようですが、DBMSは何でしょうか?

スキルアップ/キャリアアップ(JOB@IT)