none
コンボボックスのデータをIndexで検索したいのですが、うまくいきません。 RRS feed

  • 質問

  • VB2010 Express, SQLサーバー2000を使用しています。

    サーバーからデータを引き出し、それをコンボボックスに複数列で表示しています。 コンボボックスの選択・表示自体はうまくいっていますので問題ありません。

    コンボからデータ選択後に、関連データを他のテキストボックスに表示します。 これが、うまくいきません。 

    Option Strict Offでは上記事項も成功していたのですが、Option Strict Onにしたら、うまくいきません(方法の詳細は、省きます。 長くなりますので)。

    コンボ選択時に選択行のIndexは決定されるので(SelectedIndexで)、これを使えばそのデータ行が検索できるはずと考えました。 

    検索が成功すれば、他のテキストボックスへの関連データの表示はうまくいきます。 

    ですが、その検索がうまくいきません。 最後に、コードを示します。 

    ひょっとしたら、コンボボックスにはIndexはあるけど、データテーブル自体にはIndexはないのでしょうか、としたらこの方法自体が的外れになりますが。

    下記コード中の”dtcmb”--- サーバーから引き出してきたデータテーブルです。

         〃    ”Me.CB_ParentClient_ID” ----- コンボボックスです。

    このテーブルの中から、目的のIndexをもつ行を検索したいのです。 下記コード中の「?」にいろいろ入れてみたのですが、ダメでした。

    また、Selectの代わりに、他にもいろいろ実験したのですが、----。

    よろしく、ご教示をお願いします。

    Yksaila

         Dim PCLID_INDX As Integer = Me.CB_ParentClient_ID.SelectedIndex
            Dim foundrows() As Data.DataRow
            foundrows = dtcmb.Select(" ? ")
           

    2012年5月30日 2:17

回答

  • こんばんは。

    それでは、以下では如何でしょう?("Tostring"を追加)

    Me.CB_ParentClient_ID.text = dtcmb.rows(PCLID_INDX).item("Client_ID").Tostring

    • 回答としてマーク yksaila 2012年5月30日 15:16
    2012年5月30日 14:11
  • nplaceazureさんへ

    できました、細部もOKでした。 

    あまりにも、私はFoundrowsに、こだわり過ぎていたようです。 trapemiyaさんの言われる、Selectでなくバインド先のDataRowをつかむ、というのは、このことだったんですね。

    うっかりしていました、他では使っていたのに、なぜ気付かなかったのでしょう。 まだまだ修行が足りない(初心者だから、当然ですけど)、ということですね。

    今夜は徹夜かと覚悟していたのですが、安心して眠れます。

    本当に、助かりました、ありがとうございます。 下記に、修正コードの一部を記載します。 「’」のつく行は、参考までに残しました(旧コードです)。

    YKsaila

    以下、コードです:

     '親会社(本店)のデータ行検索---(Me.CB_ParentClient_ID.Text)--親会社のClient_IDを探す。
            Dim PCLIDN As String = Me.CB_ParentClient_ID.Text ’---親会社の表示名
            Dim PCLID_INDX As Integer = Me.CB_ParentClient_ID.SelectedIndex  ’---コンボ選択時のINDEX

            'データがない時は、Exit。
            Dim foundrows() As Data.DataRow
            foundrows = dtcmb.Select("ShortName= '" & PCLIDN & "'")  '---上記データテーブル(dtcmb)で、親会社(本店)の表示名(ShortName)でデータ行検索
            If foundrows.Count = 0 Then                         ’---ここは、存在確認だけなので同一名の別会社でもOK(ID・Codeが一致しなくても良い)
                Exit Sub
            End If

            Me.TX_ParentClientCode.Text = dtcmb.Rows(PCLID_INDX).Item("ClientCode").ToString
            'Me.TX_ParentClientCode.Text = foundrows(0).Item("ClientCode").ToString

            Me.TX_ClientCode.Text = dtcmb.Rows(PCLID_INDX).Item("ClientCode").ToString
            'Me.TX_ClientCode.Text = foundrows(0).Item("ClientCode").ToString

            Me.TX_ParentClient_ID.Text = dtcmb.Rows(PCLID_INDX).Item("Client_ID").ToString
            'Me.TX_ParentClient_ID.Text = foundrows(0).Item("Client_ID").ToString

            Dim PCLID As Integer
            'PCLID = CInt(foundrows(0).Item("Client_ID"))   ' 子会社のParentClient_IDを、自己のClient_IDとして持つ会社、つまり親会社のClient_IDである。  以下で使用する。
            PCLID = CInt(dtcmb.Rows(PCLID_INDX).Item("Client_ID").ToString)
            '子会社を複数検索:親会社のClient_ID(=PCLID)で、子会社を複数検索(子会社のParentClient_ID=PCLID-----同一の親会社を持つ会社を全て検索)
        ------
        あとは、省略(長いので)


    • 回答としてマーク yksaila 2012年5月30日 15:16
    • 編集済み yksaila 2012年5月30日 15:21
    2012年5月30日 15:14

すべての返信

  • Option Strict Onにしたらうまく行かないということですが、どのようにうまく行かないのでしょうか?

    基本的な考え方として、コンボボックスのSelectedIndexは、あくまでコンボボックス上でのインデックスになります。そこからコンボボックスで選択している項目を知ることができますから、その項目の情報を使ってデータテーブルのSelectメソッドを使って検索することになります。もし、コンボボックスにデータテーブルがバインドしているのであれば、Selectメソッドを使わなくても、バインド先のDataRowを取得することも可能です。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    2012年5月30日 2:32
    モデレータ
  • Option Strict Onにしたらうまく行かないということですが、どのようにうまく行かないのでしょうか?

    基本的な考え方として、コンボボックスのSelectedIndexは、あくまでコンボボックス上でのインデックスになります。そこからコンボボックスで選択している項目を知ることができますから、その項目の情報を使ってデータテーブルのSelectメソッドを使って検索することになります。もし、コンボボックスにデータテーブルがバインドしているのであれば、Selectメソッドを使わなくても、バインド先のDataRowを取得することも可能です。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    早速のご教示、ありがとうございます。 病み上がりで頭が少しぼおっとしていたので、二つの問題を混合させていたようです。 すいません。

    >Option Strict Onにしたらうまく行かないということですが、どのようにうまく行かないのでしょうか?

    基本的なことは、解決しています。 型の一致、ASの使用等々です(100個所近くありました)。 残りは、遅延バインディング関連の対策のみです。

    >コンボボックスのSelectedIndexは、あくまでコンボボックス上でのインデックスになります。

    やはり、そうでしたか。 では、別の方法を、まず試みてみます。

    バインド先のDataRow取得の方法も、考えて見ます。 分からなければ、再度質問しますので、その時はよろしくお願いします。

    Yksaila

    2012年5月30日 7:13
  • Option Strict Onにしたらうまく行かないということですが、どのようにうまく行かないのでしょうか?

    基本的な考え方として、コンボボックスのSelectedIndexは、あくまでコンボボックス上でのインデックスになります。そこからコンボボックスで選択している項目を知ることができますから、その項目の情報を使ってデータテーブルのSelectメソッドを使って検索することになります。もし、コンボボックスにデータテーブルがバインドしているのであれば、Selectメソッドを使わなくても、バインド先のDataRowを取得することも可能です。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    trapemiyaさんへ

    >Selectメソッドを使わなくても、バインド先のDataRowを取得することも可能です。
    バインド先のDataRow取得方法を、教えてくださいますか。

    なお、関連事項の例を示します。

    コンボボックスで、列は一個のみの表示です。 データテーブル(dtcmb、サーバーから引いてきたもの)には、Client_ID、ClientCode、ShortNameの3個の列があります。

    Client_IDは数値、残りは文字型、ShortNameは通常の名前です。 コンボにはShortNameのみ表示されます。

    ---この状態でコンボ選択です。 選択すると、隣のテキストボックス(2個)に、選択データのClient_IDやClientCodeを表示します。

    このShortNameには、別人で同一名(例:Aさんとします)が存在します(これは、避けられません。 出来れば、この名前の登録時に印等をつけての区別は、したくないのです)。 この状態でコンボボックスを選択すると、最初のShortNameしか選びません。 当然ですね、その表示名で検索しますので。 最初のAを選んでも、二個目のAを選んでも、IDやCodeは最初のものしか表示しません。

    二個目のAさんを選んだときは、一個目のAさんのではなく、二個目のAさんのCLIENT_IDやClientCodeを隣のテキストボックスに表示したいのです。

    DisplayMember,ValueMember,SelectedText----,種々試しましたがダメでした。 

    コンボ選択時でのDtaRowが取得できれば、解決できると思います。

    よろしく、お願いします。

    YKsaila

    2012年5月30日 8:09
  • 特定の項目を見つけるには、一意なキーがなければ不可能な気がします。

    解決策として、ComboBoxには一覧のアイテムと対応する内部的な値を設定する事ができるので
    内部値として一意なキーとなる値を持たせる、などという方法もあります。

    ↓ご参考までに。
    http://www.r-nakai.com/archives/25
    http://www.r-nakai.com/archives/29

    2012年5月30日 8:24
  • 初めまして
    最初の質問の
    >ひょっとしたら、コンボボックスにはIndexはあるけど、データテーブル自体にはIndexはないのでしょうか
    ですがデータテーブル自体のindexとは行の位置のことでしょうか?

    もしかして、コンボボックスのデータの並び順とデータテーブルの並び順は同じという前提で、コンボボックスで
    2番目のデータを選択されたならば、データテーブルの2行目のデータを表示したいということですか?

    そうならば以下の記述で解決できると思います。

    Dim PCLID_INDX As Integer = Me.CB_ParentClient_ID.SelectedIndex
    テキストボックスClient_ID.text = dtcmb.rows(PCLID_INDX).item("Client_ID")
    テキストボックスClientCode.text = dtcmb.rows(PCLID_INDX).item("ClientCode")

    間違ってたら、すみません。

    ちなみに、データテーブルのselectメソッドを使うとすると

    Dim foundrows() As Data.DataRow
    foundrows = dtcmb.Select("ShortName = '" & Me.CB_ParentClient_ID.SelectedItem & "'")

    とかするしかなく、結果、  foundrowsには、同じShortNameの値を持つ複数行のデータが格納されてしまうので、

    NF64さんの対応して、コンボボックスにClient_IDの値を格納して、データテーブルのselectメソッドではShortName

    ではなく、Crient_Idでフィルタかけて、1行を特定する必要があります。(Crient_Idで1行特定できる前提)

         



    • 編集済み nplaceazure 2012年5月30日 12:59 追記
    2012年5月30日 12:27
  • 初めまして
    最初の質問の
    >ひょっとしたら、コンボボックスにはIndexはあるけど、データテーブル自体にはIndexはないのでしょうか
    ですがデータテーブル自体のindexとは行の位置のことでしょうか?

    もしかして、コンボボックスのデータの並び順とデータテーブルの並び順は同じという前提で、コンボボックスで
    2番目のデータを選択されたならば、データテーブルの2行目のデータを表示したいということですか?

    そうならば以下の記述で解決できると思います。

    Dim PCLID_INDX As Integer = Me.CB_ParentClient_ID.SelectedIndex
    テキストボックスClient_ID.text = dtcmb.rows(PCLID_INDX).item("Client_ID")
    テキストボックスClientCode.text = dtcmb.rows(PCLID_INDX).item("ClientCode")

    間違ってたら、すみません。

    ちなみに、データテーブルのselectメソッドを使うとすると

    Dim foundrows() As Data.DataRow
    foundrows = dtcmb.Select("ShortName = '" & Me.CB_ParentClient_ID.SelectedItem & "'")

    とかするしかなく、結果、  foundrowsには、同じShortNameの値を持つ複数行のデータが格納されてしまうので、

    NF64さんの対応して、コンボボックスにClient_IDの値を格納して、データテーブルのselectメソッドではShortName

    ではなく、Crient_Idでフィルタかけて、1行を特定する必要があります。(Crient_Idで1行特定できる前提)

         



    nplaceazureさんへ、回答ありがとうございます。

    >そうならば以下の記述で解決できると思います。

    そうなんです、私も、同じ考えでやってみたのです。 たぶん、Option Strict Offでは、うまくいくかもしれません。 じっさい、このスレッドおよび直前のスレッドの問題は、Option Strict Offでは発生せず全てうまく動いていたのです。 Onにしてから、いくつか問題が発生しています。

    お勧めの下記コードは、”Option Strict Onでは、ObjectからStringへの暗黙的な変換はできません”とエラー警告がでます。 遅延バインディング関連なのでしょう。 他でも、何回か、この種の警告が出ます。

    Me.CB_ParentClient_ID.text = dtcmb.rows(PCLID_INDX).item("Client_ID")

    >コンボボックスにClient_IDの値を格納して、データテーブルのselectメソッドではShortNameではなく、Crient_Idでフィルタかけて、1行を特定する必要があります。

    複数列表示ですよね、この方法はわかるんです。---でも、直前のスレッドにあるように、Option Strict Onでは遅延バインディング回避処理(?)をしなければなりません。

    複数列表示もOffではうまくいっていたのです、Onにしたら遅延バインディング問題が発生したので、まずはこのスレッドの問題を解決しようと計画したのです。

    が、こうなると、遅延バインディング問題のほうが先の気がしてきました。

    それと、ここでは複数列表示をしないで解決したいという別の考えもあるのです。 先々に役立つのでは、と考えてです。

    Offに戻そうかという誘惑に駆られますが、ここは、もうひと踏ん張りすべきなのでしょう。

    要するに、コンボボックスでデータ選択したときに、その元となっているデータテーブルのどの行(Row)を選択しているのかが分かれば、あとはなんとかなるのですが?

    (Option Strict On で、ですが。)

    Yksaila

    2012年5月30日 13:43
  • こんばんは。

    それでは、以下では如何でしょう?("Tostring"を追加)

    Me.CB_ParentClient_ID.text = dtcmb.rows(PCLID_INDX).item("Client_ID").Tostring

    • 回答としてマーク yksaila 2012年5月30日 15:16
    2012年5月30日 14:11
  • nplaceazureさんへ

    なんとか、できるかもしれないです。 今からやってみます。 30分後には、連絡します。

    意外と盲点だったかもしれないですね。 大急ぎで細部を点検します。

    YKsaila

    2012年5月30日 14:37
  • nplaceazureさんへ

    できました、細部もOKでした。 

    あまりにも、私はFoundrowsに、こだわり過ぎていたようです。 trapemiyaさんの言われる、Selectでなくバインド先のDataRowをつかむ、というのは、このことだったんですね。

    うっかりしていました、他では使っていたのに、なぜ気付かなかったのでしょう。 まだまだ修行が足りない(初心者だから、当然ですけど)、ということですね。

    今夜は徹夜かと覚悟していたのですが、安心して眠れます。

    本当に、助かりました、ありがとうございます。 下記に、修正コードの一部を記載します。 「’」のつく行は、参考までに残しました(旧コードです)。

    YKsaila

    以下、コードです:

     '親会社(本店)のデータ行検索---(Me.CB_ParentClient_ID.Text)--親会社のClient_IDを探す。
            Dim PCLIDN As String = Me.CB_ParentClient_ID.Text ’---親会社の表示名
            Dim PCLID_INDX As Integer = Me.CB_ParentClient_ID.SelectedIndex  ’---コンボ選択時のINDEX

            'データがない時は、Exit。
            Dim foundrows() As Data.DataRow
            foundrows = dtcmb.Select("ShortName= '" & PCLIDN & "'")  '---上記データテーブル(dtcmb)で、親会社(本店)の表示名(ShortName)でデータ行検索
            If foundrows.Count = 0 Then                         ’---ここは、存在確認だけなので同一名の別会社でもOK(ID・Codeが一致しなくても良い)
                Exit Sub
            End If

            Me.TX_ParentClientCode.Text = dtcmb.Rows(PCLID_INDX).Item("ClientCode").ToString
            'Me.TX_ParentClientCode.Text = foundrows(0).Item("ClientCode").ToString

            Me.TX_ClientCode.Text = dtcmb.Rows(PCLID_INDX).Item("ClientCode").ToString
            'Me.TX_ClientCode.Text = foundrows(0).Item("ClientCode").ToString

            Me.TX_ParentClient_ID.Text = dtcmb.Rows(PCLID_INDX).Item("Client_ID").ToString
            'Me.TX_ParentClient_ID.Text = foundrows(0).Item("Client_ID").ToString

            Dim PCLID As Integer
            'PCLID = CInt(foundrows(0).Item("Client_ID"))   ' 子会社のParentClient_IDを、自己のClient_IDとして持つ会社、つまり親会社のClient_IDである。  以下で使用する。
            PCLID = CInt(dtcmb.Rows(PCLID_INDX).Item("Client_ID").ToString)
            '子会社を複数検索:親会社のClient_ID(=PCLID)で、子会社を複数検索(子会社のParentClient_ID=PCLID-----同一の親会社を持つ会社を全て検索)
        ------
        あとは、省略(長いので)


    • 回答としてマーク yksaila 2012年5月30日 15:16
    • 編集済み yksaila 2012年5月30日 15:21
    2012年5月30日 15:14
  • >Selectメソッドを使わなくても、バインド先のDataRowを取得することも可能です。
    バインド先のDataRow取得方法を、教えてくださいますか。

    TableAdapterを作成し、データソースからコンボボックスを配置したのであれば、BindingSource経由でコンボボックスのデータソースが設定されているはずです。であれば、以下の1行でDataRowが取得できます。

    Private Sub 会社BindingSource_CurrentChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles 会社BindingSource.CurrentChanged
        Dim dataRow = CType(Me.会社BindingSource.Current, DataRowView).Row
        System.Diagnostics.Debug.WriteLine(dataRow(1))
    End Sub

    この他、バインディングの仕組みを利用していくつか方法が考えられますが、現在はBindingSourceを使う方法がお勧めです。もちろん、ウィザードを使わずに自分でBindingSourceを利用してコンボボックスのDataSourceに設定することも可能です。バインディングの根本はBindingContextになりますので、詳しくはこのキーワードを元に調べてみて下さい。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    2012年5月31日 0:43
    モデレータ
  • trapemiyaさんへ

    ありがとうございます。

    少し難しそうですが、やってみます。

    YKsaila

    2012年5月31日 1:15
  • ちなみに選択された行の値を取るだけであれば、以下のように書けます。

    Me.会社BindingSource.Current("会社名")

    以下が参考になると思います。

    BindingSource.Current returns previous, not current
    http://social.msdn.microsoft.com/Forums/lv-LV/Vsexpressvb/thread/0211aa68-342b-4caf-a422-aaafd2ff09e8


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    2012年5月31日 1:40
    モデレータ
  • >Selectメソッドを使わなくても、バインド先のDataRowを取得することも可能です。
    バインド先のDataRow取得方法を、教えてくださいますか。

    TableAdapterを作成し、データソースからコンボボックスを配置したのであれば、BindingSource経由でコンボボックスのデータソースが設定されているはずです。であれば、以下の1行でDataRowが取得できます。

    Private Sub 会社BindingSource_CurrentChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles 会社BindingSource.CurrentChanged
        Dim dataRow = CType(Me.会社BindingSource.Current, DataRowView).Row
        System.Diagnostics.Debug.WriteLine(dataRow(1))
    End Sub

    この他、バインディングの仕組みを利用していくつか方法が考えられますが、現在はBindingSourceを使う方法がお勧めです。もちろん、ウィザードを使わずに自分でBindingSourceを利用してコンボボックスのDataSourceに設定することも可能です。バインディングの根本はBindingContextになりますので、詳しくはこのキーワードを元に調べてみて下さい。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    trapemiyaさんへ

    ありがとうございます。

    >TableAdapterを作成し、データソースからコンボボックスを配置したのであれば
    私の方法は、ひょっとして上記の方法でないのかもしれません? Handles以降の、BindingSourceの部分が波線でエラーになります。

    私は、毎回次のようにしています:

    -----(省略)

    con.open() ---- サーバーへの接続

    Dim adapter = New Sqlclient.Sqladapter()

    -----(省略)

    Dim dscmb = New DataSet

    Dim dtcmb as New Datatable

    dtcmb=dscmb.Tables(0) ----サーバーから引き出してきたデータテーブル

    -----(省略)

     Con.Close()

            dtcmb.Dispose()  
            adapter.Dispose()
            sql.Dispose()
            Con.Dispose()

    End Sub

    コンボボックス.DataSource=dtcmb → 今回はこの行は使用しません。 使用するとおかしくなります。 最後の dtcmb.dispose()を使用不可にすると、他がダメになります。

    私のやり方は、TableAdapterの作成ではないのでしょうか? 現段階では不自由していません、動作も速いです。

    データ・バインディングの基本がまだ理解できていませんので、これについては、これから勉強していきます。 

    上記の私の方法で問題なければ、このまま続けていこうと考えています。

    YKsaila


    • 編集済み yksaila 2012年5月31日 1:53
    2012年5月31日 1:52
  • >コンボボックス.DataSource=dtcmb → 今回はこの行は使用しません。 使用するとおかしくなります。 最後の dtcmb.dispose()を使用不可にすると、他がダメになります。

    DataSourceを利用した方が楽に開発ができますし、コードが完結になり、メンテナンスも楽になります。私が一つ前の投稿で紹介したページのコードを見てみて下さい。

    >私のやり方は、TableAdapterの作成ではないのでしょうか? 現段階では不自由していません、動作も速いです。

    TableAdapterの作成ではありません。TableAdapterについては下で説明します。

    >上記の私の方法で問題なければ、このまま続けていこうと考えています。

    その方法が間違っているわけではありません。ある機能を実装するにはいろいろな方法があります。どのような方法を選択するのかはポリシーによると思います。ただ、一般的に推薦される方法というのは存在します。
    SqlDataAdapter, DataSet, DataTableを直接使用する方法は、ADO.NETの初期の開発方法です。もちろん、この方法は今では主役ではなくなりましたが、必要な時もあります。ですから、ADO.NETに関してきちんと理解することは、コーディングの幅を広げることにつながります。
    では、今の主役は何でしょうか? それはTableAdapterです。ADO.NETを使うには、SqlDataAdapter, DataSet, DataTableなどを学習し、コーディングも決して短く済むわけではありませんでした。しかも、毎回同じようなコードを書くことになります。そこで、楽をするために、TableAdapterが生まれました。TableAdapterの内部ではSqlDataAdapter, DataSet, DataTableを駆使して、yksailaさんが書かれているようなことを行っています。つまり、TableAdapterはSqlDataAdapter, DataSet, DataTableなどを楽に使うためのユーティリティクラスなのです。ウィザードに従うと、Visual Studioが自動でこのクラスを書いてくれます。
    ちなみにTableAdapterと同じようなコンセプトで生まれてきたのがBindingSourceです。これも楽をするためにVisual Studioが作成してくれるユーティリティクラスです。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    2012年5月31日 2:14
    モデレータ
  • >コンボボックス.DataSource=dtcmb → 今回はこの行は使用しません。 使用するとおかしくなります。 最後の dtcmb.dispose()を使用不可にすると、他がダメになります。

    DataSourceを利用した方が楽に開発ができますし、コードが完結になり、メンテナンスも楽になります。私が一つ前の投稿で紹介したページのコードを見てみて下さい。

    >私のやり方は、TableAdapterの作成ではないのでしょうか? 現段階では不自由していません、動作も速いです。

    TableAdapterの作成ではありません。TableAdapterについては下で説明します。

    >上記の私の方法で問題なければ、このまま続けていこうと考えています。

    その方法が間違っているわけではありません。ある機能を実装するにはいろいろな方法があります。どのような方法を選択するのかはポリシーによると思います。ただ、一般的に推薦される方法というのは存在します。
    SqlDataAdapter, DataSet, DataTableを直接使用する方法は、ADO.NETの初期の開発方法です。もちろん、この方法は今では主役ではなくなりましたが、必要な時もあります。ですから、ADO.NETに関してきちんと理解することは、コーディングの幅を広げることにつながります。
    では、今の主役は何でしょうか? それはTableAdapterです。ADO.NETを使うには、SqlDataAdapter, DataSet, DataTableなどを学習し、コーディングも決して短く済むわけではありませんでした。しかも、毎回同じようなコードを書くことになります。そこで、楽をするために、TableAdapterが生まれました。TableAdapterの内部ではSqlDataAdapter, DataSet, DataTableを駆使して、yksailaさんが書かれているようなことを行っています。つまり、TableAdapterはSqlDataAdapter, DataSet, DataTableなどを楽に使うためのユーティリティクラスなのです。ウィザードに従うと、Visual Studioが自動でこのクラスを書いてくれます。
    ちなみにTableAdapterと同じようなコンセプトで生まれてきたのがBindingSourceです。これも楽をするためにVisual Studioが作成してくれるユーティリティクラスです。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    trapemiyaさんへ

    ありがとうございました。

    この種のツール(?)があることは知っており、いずれは使用すべきと感じておりました。 そろそろ、始めるべき時期ですね。

    最初は学習のためと思い、現在の手法で始めました。 いつまでも、この手法ですと、効率が悪いですね。 すでにVBの有料版も購入済み(3か月前)なのですが、勉強と面倒が理由でExpress版を使用し続けてています。

    VBについて何も理解していないで即ツールは、自分にとってためにならないですから。 お勧めのアドレスにもアクセスし、勉強します。

    関連で、お尋ねします:実は、いつも念頭に置いているのが、”排他処理”です。 私のソフトが完成するまでには、フォームが約50~60あります。 現在完成のフォームは、3個!

    サーバーに接続し、クライアントは最低十数台、できれば100台近くまで使用できるもの、という遠大な計画を立てています(実現するかは、まあ別問題ですけど)。

    100台を超えると(別に100にこだわっているのではないです、60台でもいいのですが)、ネットワーク関係で別の問題がでてくると聞いています。 ですから、一応は、そこまで。

    多くのクライアントが同時に使用するときには、”排他処理”は避けられない重要問題です。 市販のソフトでも、中には”排他処理”が十分になされておらず、エラーがでるものが、あるような気がします。

    この場合に、TableAdapterやBindingsSourceを使用しても、使用しないのと同じレベルで排他処理は装着できますか? なぜか、感覚的に当初の手法のほうが”排他処理”を進めていくには良いような気もしていたのです(学習もしないでの、ただの感覚にすぎないのですが)。 同じですか?

    では、今後もよろしく、お願いします。

    先は、気が遠くなるほど長いのかも? でも、一歩ずつですね。

    YKsaila

    2012年5月31日 6:20
  • この場合に、TableAdapterやBindingsSourceを使用しても、使用しないのと同じレベルで排他処理は装着できますか? なぜか、感覚的に当初の手法のほうが”排他処理”を進めていくには良いような気もしていたのです(学習もしないでの、ただの感覚にすぎないのですが)。 同じですか?

    排他処理に関係するのはTableAdapterであり、BindingSourceは関係ありません。排他処理はTableAdapterを作成するウィザードの途中に「オプティミスティック同時実行制御」という項目がありますので、そこにチェックを入れることにより自動的に組み込まれます。データベースにSQL Serverをお使いの場合、TIMESTAMP型の列を用意しておくと、効率のよいオプティミスティック同時実行制御を行うUpdate文が生成されます。TIMESTAMP型の列が無くてもオプティミスティック同時実行制御を行うUpdate文は生成されますが、自分がこれから更新する前に、自分が読み込んでからそのレコードを誰かが変更していないか確認するために、そのレコードの全項目が変更されていないか確認することになります(※1)。これがオプティミスティック同時実行制御の原理です。TIMESTAMP型の列があれば、この列だけを比較することになりますので、効率が良くなります。

    TableAdapterを使用せずにYKsailaさんがされている方法の場合、TableAdapterが自動的に組み込んだオプティミスティック同時実行制御と同じものを自分で組み込まなければなりません。同じオプティミスティック同時実行制御を行うために、Visual Studioの力を借りるか(つまり、TableAdapterの使用するか)、全て自分で記述するかの違いになります。今後の開発工数を考えれば、やはりTableAdapterの使用をお勧めします。

    (追記)
    ※1 正確には確認してから更新するのではありません。自分が読んでからレコードが変更されていない前提でUpdate文を実行し、更新件数が0件だと他の誰かが更新したということになります。例えば、A, B, Cと3列あるレコードの場合、
    update hogeTable set A=新しいA where A=自分が読んできたときのAの値 and B=自分が読んできたときのBの値 and C=自分が読んできたときのCの値
    というSQL文になります。
    もし、A, B, C, DでTIMESTAMP型のD列がある場合、
    update hogeTable set A=新しいA where D=自分が読んできたときのDの値
    と簡単になります。TIMESTAMP型の列は、列が更新される度に新しい値になるからです。
    以上のようにupdate文を発行すれば、YKsailaさんが現在行っているままでも、つまりTableAdapterを使わなくても、オプティミスティック同時実行制御は実現できます。

    #シームレス的に当初の質問とは違う話題になってきていますので、追加で質問する場合は、一旦このスレッドを閉じ、新しくスレッドを作成して下さい。ご協力をお願いいたします。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/




    2012年5月31日 6:43
    モデレータ
  • trapemiyaさんへ

    ありがとうございました。

    参考になりました。 つい、流れで横道にそれてしまいました。 

    すいません、以後気をつけます。

    YKsaila


    • 編集済み yksaila 2012年5月31日 7:46
    2012年5月31日 7:45