トップ回答者
2つのテーブルを一括更新する方法を教えてください

質問
-
データベースに
テーブル1------
NO / 名前
テーブル2------
ban / NO / TEL
としてデータセットで
SELECT:テーブル1.NO, テーブル1.名前, テーブル2.tel
FROM:テーブル1 INNER JOIN
テーブル2 ON テーブル1.NO = テーブル2.NO
をつくりました。それを一括更新できるようにしたいのですが
2つのテーブルをつけたものでは一括更新ができないのでしょうか?http://msdn.microsoft.com/ja-jp/library/aa992036(VS.80).aspx
のページで、1つのテーブルでしたら一括更新ができるのですが・・・
どのようにしたら2つのテーブルが一括更新できるのでしょうか?教えてください。<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>無題のページ</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataSourceID="ObjectDataSource1">
<Columns>
<asp:BoundField DataField="NO" HeaderText="NO" SortExpression="NO" />
<asp:TemplateField HeaderText="名前" SortExpression="名前">
<ItemTemplate>
<asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("名前") %>'></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="tel" SortExpression="tel">
<ItemTemplate>
<asp:TextBox ID="TextBox2" runat="server" Text='<%# Bind("tel") %>'></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<aspbjectDataSource ID="ObjectDataSource1" runat="server"
OldValuesParameterFormatString="original_{0}" SelectMethod="GetData"
TypeName="DataSet1TableAdapters.DataTable1TableAdapter">
</aspbjectDataSource>
</div>
</form>
</body>
</html>
回答
-
どこまでコーディングレスでできるか試してみましたが、1行もコードを書かずに
というのは無理っぽいです。でも、ADO.NET ライブラリを使わなくてもなんとかなります。また、GridView の
UpdateRow メソッドを使って、GridView 上の複数行のデータ変更を2つのテーブ
ルに反映する(2つのテーブルを同時に UPDATE する)ことも可能です。たぶん、komi1 さんは、ウィザードベースで DataSet + TableAdapter(.xsd ファ
イル)を作って、クエリビルダで SELECT クエリを作っていると思いますが、とす
ると、その先以下のような方法で実現できるはずです。(1) .xsd ファイルを開いて、その TableAdapter にツールボックスから Query を
ドラッグ&ドロップ。クエリビルダで「テーブル1」を UPDATE するクエリを
作り、適当なメソッド名(例: UpdateQuery1)をつけて保存。(2) 同様に、「テーブル2」を UPDATE するクエリを作り、適当なメソッド名(例:
UpdateQuery2)をつけて保存。(3) App_Code フォルダにクラスファイルを追加。UpdateQuery1 と UpdateQuery2
を使って2つのテーブルを UPDATE するメソッドを TableAdapter の partial
class として実装する。ここは自力でコードを書く必要があります。以下のよ
うな感じです。Code Snippetusing System;
using System.Data;
using System.Collections.Generic;
using System.Web;
using System.Transactions;namespace XxxxxTableAdapters
{
public partial class XxxxxxTableAdapter
{
[System.ComponentModel.DataObjectMethod(System.ComponentModel.DataObjectMethodType.Update)]
public int UpdateTwoTables(int original_no, string name, string tel)
{
int returnValue;using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
returnValue = this.UpdateQuery1(name, original_no);
returnValue += this.UpdateQuery2(tel, original_no);
scope.Complete();
}
return returnValue;
}
}
}(4) ObjectDataSource の「データソースの構成」で UPDATE メソッドに上記 (3) の
メソッドを選択する。(5) GridView を上記の ObjectDataSource に接続し、参考にした Web ページに従っ
て、Template を編集し、コードを実装する(一部間違いらしきところがあるの
で注意)。上記で (3) のところだけは自力でコードを書く必要がありますが、その他はすべて
ウィザードベースでコードを書かずに実装できるはずです。 -
ありがとうございます。
ただ、コードをクラスファイルに貼り付けたのですが
青い波線がたくさん出てしまう状態です。
何か手順をまちがえているのでしょうか?DataSetを作りTableAdapterに
Table1、Table2の全項目を出力させました。
Table1: NO , 名前
Table2: ban , NO , TEL次にQueryで「Table1: NO , 名前」を出力にチェックをつけ
GetMethodNameを UpdateQuery1とつけて保存。同様に、「Table2: ban , NO , TEL 」を出力にチェックをつけ
GetMethodNameを UpdateQuery2とつけて保存させました。そしてApp_Code フォルダにクラスファイルを追加し中身は
Imports Microsoft.VisualBasic
Public Class Class1
End Classと3行だけなんですが教えていただいたコードを貼り付けました。
Imports Microsoft.VisualBasic
Public Class Class1
End Class
using System;
using System.Data;
using System.Collections.Generic;
using System.Web;
using System.Transactions;namespace XxxxxTableAdapters
{
public partial class XxxxxxTableAdapter
{
[System.ComponentModel.DataObjectMethod(System.ComponentModel.DataObjectMethodType.Update)]
public int UpdateTwoTables(int original_no, string name, string tel)
{
int returnValue;using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
returnValue = this.UpdateQuery1(name, original_no);
returnValue += this.UpdateQuery2(tel, original_no);
scope.Complete();
}
return returnValue;
}
}
}こうするとたくさん青い波線がでてしまいます。
usingのところではステートメントをメソット本体の外側に表示することはできません。 -
> ただ、コードをクラスファイルに貼り付けたのですが
> 青い波線がたくさん出てしまう状態です。
> 何か手順をまちがえているのでしょうか?間違い以前の問題があるようです。正直言って、やっていることが滅茶苦
茶なんですけど。
どうもプログラムの知識はまったくお持ちでなく、コードのコピペ以外のこ
とはできないようにお見受けしますが、いかがですか? そうだとすると、
掲示板で、今回の例のようなコードが書けるまで教えるというのは、ほとん
ど不可能だと思います。本などで勉強してある程度知識をつけていただかないと、話が通じないの
で、いくら説明しても空回りに終わってしまいます。今回がそのいい例です。
と言っても、ここまで来てしまったので、話は通じないかもしれませんが、
一応回答しておきます。> DataSetを作りTableAdapterに
> Table1、Table2の全項目を出力させました。
> Table1: NO , 名前
> Table2: ban , NO , TEL最初の質問と話が違うようですが。SELECT クエリは以下のようになってい
るのですか? 違っていたら、元に戻してください。途中で変えられると話が
通じなくなります。ところで、主キーは NO ですか?
SELECT テーブル1.NO, テーブル1.名前, テーブル2.tel FROM テーブル1 INNER JOIN
テーブル2 ON テーブル1.NO = テーブル2.NO> 次にQueryで「Table1: NO , 名前」を出力にチェックをつけ
> GetMethodNameを UpdateQuery1とつけて保存。上記の手順で作ったクエリはどうなっていますか? ちゃんと、
UPDATE [テーブル1] SET 名前 = @名前 WHERE NO = @NO
というようなクエリができていて、メソッドの引数も @名前、@NO というよう
になっていますか?> 同様に、「Table2: ban , NO , TEL 」を出力にチェックをつけ
> GetMethodNameを UpdateQuery2とつけて保存させました。上記の手順でも、ちゃんと UPDATE クエリはできているでしょうか?
> そしてApp_Code フォルダにクラスファイルを追加し中身は
> Imports Microsoft.VisualBasic
> Public Class Class1
>
> End Class
> と3行だけなんですが教えていただいたコードを貼り付けました。ここが滅茶苦茶の最たるところです。
教えたコードはあくまでサンプルです。それを参考に自分の環境に合わせて書
き直す必要があります。まず、先のサンプルコードは C# で書かれており、VB
に書き直す必要があります。また、namespace と class 名も、.xsd ファイル
から自動生成される TableAdapter のコードに合わせて書き直す必要がありま
す。さらに、「参照の追加」で System.Transactions を加え、管理ツールで DTC
を「開始」するといった作業も必要です。まずは、上記が理解できる程度まで勉強してください。この先はそれからでな
いと話が通じないと思います。
すべての返信
-
すみません。まだ、プログラムを自分で書けなくて
使いたいサンプルなどを修正して作っている段階の初心者でよくわからないのですが
UpdateButton_Clickのボタンのところを修正するということですよね?
どのように修正したらいいのかわからないのですが?
教えていただけないでしょうか?
また、何か参考になるHPなどはあるでしょうか?
Protected Sub UpdateButton_Click(ByVal sender As Object, ByVal e As EventArgs)
originalDataTable = CType(ViewState("originalValuesDataTable"), System.Data.DataTable)
For Each r As GridViewRow In GridView1.Rows
If IsRowModified(r) Then GridView1.UpdateRow(r.RowIndex, False)
Next
' Rebind the Grid to repopulate the original values table.
tableCopied = False
GridView1.DataBind()
End Sub -
以下のページの一番最後に掲載されているtransactionscopeで囲まれたコードが参考になります。
社員テーブルから削除する 3
http://archive.mag2.com/0000128094/20080723093000000.html上で掲載されているコードを以下のように修正します。
1.掲載されているコードでは削除をしていますが、それを更新を行うSQLに変更します。ただし、SQLインジェクションの恐れがありますので、パラメタライズドクエリに変更します。パラメタライズドクエリに関しては以下を参考にして下さい。
SqlCommand1.Parameters.AddWithValueとか、SqlCommand1.Parameters.Addを使う部分です。同IDの2つのTableへInsert
http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=3687396&SiteID=72.上記の更新のSQLを2つのテーブルに対して2回発行します。
以上で2つのテーブルが更新されるはずです。
他の方法として、一つのupdate文はアトミック(部分的に更新されるという中途半端なことはない))ですので、一つのupdate文で二つのテーブルを更新できるのであれば、そちらが簡単です。
-
komi1 さんからの引用
トランザクションやADO.NETっていうんですよね?を、知らなかったので戸惑っています。
ADO.NETは、SqlDataSource、TableAdapter、LINQ to SQLなどにより隠蔽されることが多くなってきましたが、少し複雑なこと行う場合には、ADO.NETを直接扱わなければならない場合があります。そのため、ADO.NETの知識は、データベースを扱うプログラムを書く場合は避けて通れないと言って良いでしょう。
また、同時にトランザクションなどデータベースの知識も大事ですので、合わせて基礎知識を付けられることを強く薦めます。komi1 さんからの引用
チュートリアルの一括更新は全く使わないということですよね?すみません。何を手を付けたらいいかわからない状態です。
For Each r As GridViewRow In GridView1.Rows
If IsRowModified(r) Then GridView1.UpdateRow(r.RowIndex, False)
Nextと書かれていますが、更新の部分をGridViewのUpdateRowメソッドを使用せず、自分でADO.NETを使って更新するコードを書けばOKです。どのようなコードを書けばよいかは、私の前回の投稿が参考になるはずです。
-
どこまでコーディングレスでできるか試してみましたが、1行もコードを書かずに
というのは無理っぽいです。でも、ADO.NET ライブラリを使わなくてもなんとかなります。また、GridView の
UpdateRow メソッドを使って、GridView 上の複数行のデータ変更を2つのテーブ
ルに反映する(2つのテーブルを同時に UPDATE する)ことも可能です。たぶん、komi1 さんは、ウィザードベースで DataSet + TableAdapter(.xsd ファ
イル)を作って、クエリビルダで SELECT クエリを作っていると思いますが、とす
ると、その先以下のような方法で実現できるはずです。(1) .xsd ファイルを開いて、その TableAdapter にツールボックスから Query を
ドラッグ&ドロップ。クエリビルダで「テーブル1」を UPDATE するクエリを
作り、適当なメソッド名(例: UpdateQuery1)をつけて保存。(2) 同様に、「テーブル2」を UPDATE するクエリを作り、適当なメソッド名(例:
UpdateQuery2)をつけて保存。(3) App_Code フォルダにクラスファイルを追加。UpdateQuery1 と UpdateQuery2
を使って2つのテーブルを UPDATE するメソッドを TableAdapter の partial
class として実装する。ここは自力でコードを書く必要があります。以下のよ
うな感じです。Code Snippetusing System;
using System.Data;
using System.Collections.Generic;
using System.Web;
using System.Transactions;namespace XxxxxTableAdapters
{
public partial class XxxxxxTableAdapter
{
[System.ComponentModel.DataObjectMethod(System.ComponentModel.DataObjectMethodType.Update)]
public int UpdateTwoTables(int original_no, string name, string tel)
{
int returnValue;using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
returnValue = this.UpdateQuery1(name, original_no);
returnValue += this.UpdateQuery2(tel, original_no);
scope.Complete();
}
return returnValue;
}
}
}(4) ObjectDataSource の「データソースの構成」で UPDATE メソッドに上記 (3) の
メソッドを選択する。(5) GridView を上記の ObjectDataSource に接続し、参考にした Web ページに従っ
て、Template を編集し、コードを実装する(一部間違いらしきところがあるの
で注意)。上記で (3) のところだけは自力でコードを書く必要がありますが、その他はすべて
ウィザードベースでコードを書かずに実装できるはずです。 -
ありがとうございます。
ただ、コードをクラスファイルに貼り付けたのですが
青い波線がたくさん出てしまう状態です。
何か手順をまちがえているのでしょうか?DataSetを作りTableAdapterに
Table1、Table2の全項目を出力させました。
Table1: NO , 名前
Table2: ban , NO , TEL次にQueryで「Table1: NO , 名前」を出力にチェックをつけ
GetMethodNameを UpdateQuery1とつけて保存。同様に、「Table2: ban , NO , TEL 」を出力にチェックをつけ
GetMethodNameを UpdateQuery2とつけて保存させました。そしてApp_Code フォルダにクラスファイルを追加し中身は
Imports Microsoft.VisualBasic
Public Class Class1
End Classと3行だけなんですが教えていただいたコードを貼り付けました。
Imports Microsoft.VisualBasic
Public Class Class1
End Class
using System;
using System.Data;
using System.Collections.Generic;
using System.Web;
using System.Transactions;namespace XxxxxTableAdapters
{
public partial class XxxxxxTableAdapter
{
[System.ComponentModel.DataObjectMethod(System.ComponentModel.DataObjectMethodType.Update)]
public int UpdateTwoTables(int original_no, string name, string tel)
{
int returnValue;using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
returnValue = this.UpdateQuery1(name, original_no);
returnValue += this.UpdateQuery2(tel, original_no);
scope.Complete();
}
return returnValue;
}
}
}こうするとたくさん青い波線がでてしまいます。
usingのところではステートメントをメソット本体の外側に表示することはできません。 -
> ただ、コードをクラスファイルに貼り付けたのですが
> 青い波線がたくさん出てしまう状態です。
> 何か手順をまちがえているのでしょうか?間違い以前の問題があるようです。正直言って、やっていることが滅茶苦
茶なんですけど。
どうもプログラムの知識はまったくお持ちでなく、コードのコピペ以外のこ
とはできないようにお見受けしますが、いかがですか? そうだとすると、
掲示板で、今回の例のようなコードが書けるまで教えるというのは、ほとん
ど不可能だと思います。本などで勉強してある程度知識をつけていただかないと、話が通じないの
で、いくら説明しても空回りに終わってしまいます。今回がそのいい例です。
と言っても、ここまで来てしまったので、話は通じないかもしれませんが、
一応回答しておきます。> DataSetを作りTableAdapterに
> Table1、Table2の全項目を出力させました。
> Table1: NO , 名前
> Table2: ban , NO , TEL最初の質問と話が違うようですが。SELECT クエリは以下のようになってい
るのですか? 違っていたら、元に戻してください。途中で変えられると話が
通じなくなります。ところで、主キーは NO ですか?
SELECT テーブル1.NO, テーブル1.名前, テーブル2.tel FROM テーブル1 INNER JOIN
テーブル2 ON テーブル1.NO = テーブル2.NO> 次にQueryで「Table1: NO , 名前」を出力にチェックをつけ
> GetMethodNameを UpdateQuery1とつけて保存。上記の手順で作ったクエリはどうなっていますか? ちゃんと、
UPDATE [テーブル1] SET 名前 = @名前 WHERE NO = @NO
というようなクエリができていて、メソッドの引数も @名前、@NO というよう
になっていますか?> 同様に、「Table2: ban , NO , TEL 」を出力にチェックをつけ
> GetMethodNameを UpdateQuery2とつけて保存させました。上記の手順でも、ちゃんと UPDATE クエリはできているでしょうか?
> そしてApp_Code フォルダにクラスファイルを追加し中身は
> Imports Microsoft.VisualBasic
> Public Class Class1
>
> End Class
> と3行だけなんですが教えていただいたコードを貼り付けました。ここが滅茶苦茶の最たるところです。
教えたコードはあくまでサンプルです。それを参考に自分の環境に合わせて書
き直す必要があります。まず、先のサンプルコードは C# で書かれており、VB
に書き直す必要があります。また、namespace と class 名も、.xsd ファイル
から自動生成される TableAdapter のコードに合わせて書き直す必要がありま
す。さらに、「参照の追加」で System.Transactions を加え、管理ツールで DTC
を「開始」するといった作業も必要です。まずは、上記が理解できる程度まで勉強してください。この先はそれからでな
いと話が通じないと思います。
-
vbに修正しました。
Imports System
Imports System.Data
Imports System.Collections.Generic
Imports System.Web
Imports System.TransactionsNamespace XxxxxTableAdapters
Public Partial Class XxxxxxTableAdapter
<System.ComponentModel.DataObjectMethod(System.ComponentModel.DataObjectMethodType.Update)> _
Public Function UpdateTwoTables(ByVal original_no As Integer, ByVal name As String, ByVal tel As String) As Integer
Dim returnValue As Integer
Using scope As New TransactionScope(TransactionScopeOption.RequiresNew)
returnValue = Me.UpdateQuery1(name, original_no)
returnValue += Me.UpdateQuery2(tel, original_no)
scope.Complete()
End Using
Return returnValue
End Function
End Class
End Namespace今回のことで、知識の少なさをとても感じました。
それでも、お付き合い頂いてほんとうにありがとうございました。コードをあまり、使わない初歩の本の知識しかなかったので
やはり、いろいろなことがしたいならもっと、本を読んだり勉強していかなくてはと思いました。ありがとうございました。
-
C# を VB に書き直せる知識はお持ちのようですね。(それなのに何故
VB のテンプレートに単純に C# のコードをコピペしたのか解せません。
余計なお世話は承知で言えば、知識よりもその点が問題かも。)
まず、partial class を実装する前に、下記、(1), (2) を確認ください。
(1) チュートリアルのサンプルも書き換えが必要ですが、それはきちんと
できているか?先のレスと手順が違ってしまいますが、partial class を実装する前
に、チュートリアルのコードをコピペして、自分の環境に合わせて書
き直して実行してみてください。GridView 上のデータを一箇所も変更しないときはボタンをクリック
してもエラーは出ず(例外はスローさず)、どこか一箇所でも変更し
てからボタンをクリックすると例外がスローされ「UpdateMethod が
指定されていない場合、更新操作は ObjectDataSource 'ObjectDataSource1'
によってサポートされていません。」と言うメッセージが出るはず
です。確認してください。なお、チュートリアルのコードには一部間違い(?)らしきところが
あるので注意してください。(2) 新たに作った Update のためのメソッドがきちんとできているか?
.xsd ファイルを開いて、その TableAdapter にツールボックスから
Query をドラッグ&ドロップすると、「TableAdapter クエリの構成
ウィザード」が立ち上がると思います。その「クエリの種類の選択」
メニューで「UPDATE(U)」を選択し、次に進んでクエリビルダを立ち
上げると「SQL 構文エラーが発生」と言うダイアログが出ると思いま
すが、それは無視して(OK ボタンを押して)、クエリビルダのテー
ブル欄を右クリックしてテーブルを追加し、UPDATE クエリを作って
ください。できたメソッドのプロパティを見て、その CommandText に期待した
とおりの UPDATE ができているか確認してください。
そこまで確認できたら、partial class を実装してください。namespace
名とクラス名が不明のようですが、ObjectDataSource の中の、TypeName="DataSet1TableAdapters.DataTable1TableAdapter"
で、DataSet1TableAdapters が namespace、DataTable1TableAdapter
がクラス名のはずです。(本当は、.xsd ファイルから自動生成される
TableAdapter のコードを見ると確実なんですが、とりあえず上記に変
更してインテリセンスが働けば多分OK だと思います。)
また、Transaction は UPDATE できるかどうかを試すだけなら不要です
ので、とりあえず以下の行はコメントアウトしておいてください。Imports System.Transactions
Using scope As New TransactionScope(TransactionScopeOption.RequiresNew)
scope.Complete()
End Using次に、ObjectDataSource の「データソースの構成」ウィザードを立ち上
げて、その「データメソッドの定義」の「UPDATE」タグの「メソッドの
選択」で上記で作ったメソッドを指定してください。ファイルを保存しないとウィザードが働かず、選択できないので注意してください。選択の結果、
ObjectDataSource1 のソースを見て、
UpdateMethod="UpdateTwoTables"
が追加されていれば OK です。
それでとりあえず UPDATE できるか試してみてください。
そこまでできたら Transaction を実装してください。方法が分からなけ
れば、聞いてください。