none
TableAdapterを利用する場合の文字列操作 RRS feed

  • 質問

  • こんばんは。

    VB2005Express+SQLServerExpressを使用しています。

    TableAdapterを利用する場合に、ある文字列を表示の際は「-」を加え、DBに保存する際は「-」をなくして保存したい
    項目があるとします。

    TableAdapterを利用しない保存の場合は、プロパティを作成し、そこの置いて上記の処理を記述することで対応が
    できました。

    しかし、TableAdapterを用いた場合、Updateを実行する前にバインドしているコントロール上で「-」を削除しておき
    保存完了後に「-」を加えるという方法しか、思いつきません。

    現在のDBやハードウェアのことを考えると、DBの構造自体に「-」が入るようにしてしまうのも一つの方法なのですが
    せっかくなので、何か方法があれば勉強をしておきたいと思い、質問をいたしました。

    私の知識不足性もあるのですが、TableAdapterはたしかに便利なのですが、保存などをする際に各データ項目に
    特段の処理を加えない場合は、非常に簡便でよいのですが、ちょっとした処理を加えたい場合など、どこにそれを
    記述すればよいかがわかりにくく、どうにもとっつきにくくも感じます。

    横道にそれてしまいましたが、上記の内容について、何か良い方法がございましたら、アドバイスお願いします。

    2010年8月19日 11:59

回答

  • > 私の場合は、なぜか「テーブル名+DataTable」というpartialクラスが作成されます。
    > これ自体は正常な動作なのでしょうか。

    partial な DataSet クラスの中に、それが作成されていますよね?
    それは正常です。
    TableAdapter に追加されるわけではありませんので、そのインテリセンスには表示されません。

    項目のプロパティを追加される先としては、「テーブル名+Row」の partial になるかと思います。
    仮にテーブル名を「Table1」とすれば、「Table1Row」というクラスが存在しますので、それの partial クラスを「Table1DataTable」の partial の中に定義します。
    そうすると、そのプロパティ実装の中では、既存する他の項目プロパティを参照できますし、他の項目プロパティと同様に「Table1DataTable[0].MyColumnProperty」のように使用できます。

    > 現状では、何がいけないのかさっぱり分からない状態です。

    型付データセットのために自動生成されるコードってわかりづらいですからね。


    ここからは別の方法になります。

    > プロパティを用いて、「Get」の際に「-」を追加、「Set」の際に「-」を削除という処理を行って
    > いたのですが、

    そのような変換を行うメソッドをどこかに作成しておき、
    Binding の Format イベントや Parse イベント
    (DataGridView であれば CellFormatting イベントや CellParsing イベント)
    を利用して変換を行うという方法はいかがですか?
    (Parse の処理は Validating や DataTable の Changing 等でも行えますが、Binding としては Parse がこの目的として用意されたものになります。)

    具体的には、たとえばすでに型付データセットから自動作成した「詳細」形式のメンテナンス画面があり、その項目の1つが Field1 だとした場合、デザイナの自動生成コードでは TextBox の Text プロパティにはすでに Binding が設定済みとなっていますが、その Binding のイベントを以下のように割り当てます。
    以下の例ではハイフンの編集を各イベントハンドラ内で直接行っていますが、変換を行うメソッドを呼び出すようにすると、保守性が良くなると思います(以下の例ではエラーチェックは省略しています)。

    public Form1()
    {
        InitializeComponent();

        var bindingField1 = field1TextBox.DataBindings["Text"];
        bindingField1.Format += new ConvertEventHandler(bindingField1_Format);
        bindingField1.Parse += new ConvertEventHandler(bindingField1_Parse);
    }

    private void bindingField1_Format(object sender, ConvertEventArgs e)
    {
        // 1234567891 → 1234-567891
        e.Value = ((string)e.Value).Insert(4, "-");
    }

    private void bindingField1_Parse(object sender, ConvertEventArgs e)
    {
        // 1234-567891 → 1234567891
        e.Value = ((string)e.Value).Remove(4, 1);
    }


    追記:
    今気づいたんですが、言語もバージョンも間違ってましたので、訂正させてください。

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'TableAdapter.Fill する前にイベントハンドラを設定する。
        Dim bindingField1 As Binding = Field1TextBox.DataBindings("Text")
        AddHandler bindingField1.Format, AddressOf bindingField1_Format
        AddHandler bindingField1.Parse, AddressOf bindingField1_Parse
    End Sub

    Private Sub bindingField1_Format(ByVal sender As Object, ByVal e As ConvertEventArgs)
        '1234567891 → 1234-567891
        e.Value = DirectCast(e.Value, String).Insert(4, "-")
    End Sub

    Private Sub bindingField1_Parse(ByVal sender As Object, ByVal e As ConvertEventArgs)
        '1234-567891 → 1234567891
        e.Value = DirectCast(e.Value, String).Remove(4, 1)
    End Sub

    • 編集済み TH01 2010年8月25日 0:54 追記
    • 回答としてマーク TI-cb400 2010年8月27日 20:00
    2010年8月23日 13:10

すべての返信

  • 一般的にはTableAdapterのpartialクラスで対応します。

    7.6.3 データコンポーネントの拡張
    http://www.atmarkit.co.jp/fdotnet/bookpreview/vs2005webapp_07/vs2005webapp_07_04.html

    ただ、この場合ですと、標示の場合は次のようなSQL文を発行すれば良いように思えます。

    select '-' + hoge列 from fugaテーブル


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2010年8月19日 15:01
    モデレータ
  • ご返答が遅くなり、申し訳ありません。

    ご提示いただいたサイトや、その他のpartialクラスに関連することを調べていました。

    partialクラスを用いることで、基本となるクラスに手を加えることなく機能を追加できるということまではわかりました。
    しかし、なかなか具体的な例というものがなく、今時分がやりたいことについて、どのようにすればよいかがわかりません。

    やりたいことは、


    10桁の数字の文字列を、4文字、6文字に分割し、その間に「-」を入れたい
    (1234567891 → 1234-567891)

    11桁の数字の文字列を、4文字、6文字、1文字に分割し、それぞれの間に「-」を入れたい
    (12345678912 → 1234-567891-2)

    単純に見易さという観点から、実現をしたいと考えております。

    DataSetのdesignerを覗いてみたのですが、コードが膨大でなかなか理解ができないのですが、テーブルの各フィールドの
    プロパティがある部分を見つけることができました。

    全てをコードで記述をする場合は、プロパティを用いて、「Get」の際に「-」を追加、「Set」の際に「-」を削除という処理を行って
    いたのですが、今回の場合は、プロパティをOverloadしたりするのでしょうか。

    partialクラスを調べているときに、同じ定義を作ることはできないとなっていたので、直接designerのプロパティを修正するのかな、
    とも思ったのですが、それではpartialクラスの意味がないので、partialクラス側で何かの処理を記述すると思うのですが、
    何を記述すればよいかが、わかりません。

    どうか、アドバイスお願い致します。

     

    2010年8月21日 19:21
  • 全てをコードで記述をする場合は、プロパティを用いて、「Get」の際に「-」を追加、「Set」の際に「-」を削除という処理を行って

    いたのですが、今回の場合は、プロパティをOverloadしたりするのでしょうか。

    partialクラスを調べているときに、同じ定義を作ることはできないとなっていたので、直接designerのプロパティを修正するのかな、
    とも思ったのですが、それではpartialクラスの意味がないので、partialクラス側で何かの処理を記述すると思うのですが、
    何を記述すればよいかが、わかりません。

    partial なクラスに「-」で区切った数字の文字列を返す別名のプロパティを追加し、それをコントロールに表示してはどうでしょうか?

     


    なかむら(http://d.hatena.ne.jp/griefworker)
    2010年8月21日 22:21
  • partialクラスを用いることで、基本となるクラスに手を加えることなく機能を追加できるということまではわかりました。
    しかし、なかなか具体的な例というものがなく、今時分がやりたいことについて、どのようにすればよいかがわかりません。

     partialクラスは難しい概念ではなく、1つのクラスの内容を別々に記述できるというだけのものです。別ファイルに分割して書いてもOKです。 

    やりたいことは、


    10桁の数字の文字列を、4文字、6文字に分割し、その間に「-」を入れたい
    (1234567891 → 1234-567891)

    11桁の数字の文字列を、4文字、6文字、1文字に分割し、それぞれの間に「-」を入れたい
    (12345678912 → 1234-567891-2) 

     ここだけ見れば書式指定子でフォーマットすれば済みます。例えば、12345678912を####-######-#でフォーマットすれば、1234-567891-2で表示されます。

    今回の場合は、プロパティをOverloadしたりするのでしょうか。

    プロパティなのでOverloadはできません。

    partialクラスを調べているときに、同じ定義を作ることはできないとなっていたので、直接designerのプロパティを修正するのかな、
    とも思ったのですが、それではpartialクラスの意味がないので、partialクラス側で何かの処理を記述すると思うのですが、
    何を記述すればよいかが、わかりません。

    xxx.designer.csはVisual Studioが自動生成するものですから、手を加えてはいけません。TableAdapterを再構成された際に、手を加えた部分は全て無くなってしまいます。したがって、手を加えた部分が無くならないようにpartialクラス側に記述するのです。前述した通り、partialクラスはあくまで1つのクラスに追記していることになりますから、やるとすればなかむらさんが書かれているように、別名でプロパティを作成することになるでしょう。
     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2010年8月22日 0:13
    モデレータ
  • ご回答ありがとうございます。

    別名のプロパティを作成し、テストをしてみたいと思います。
    (今、手元に環境がないので、家に戻ってから試してみます。)

    ところで、もともとdesignerによりバインドされたコントロールにデータが表示されるコードが記述されていると
    思うのですが、別名のプロパティを作成し、コントロール(テキストボックス)にデータを表示した場合、
    designerにより表示されたものに、上書きするように表示されるイメージとなるのでしょうか。

    それとも、もともとの動作自体がなかったものとなってしますのでしょうか。

    とくに知る必要はないとは思うのですが、気になってしょうがないものですから。

    2010年8月22日 6:12
  • 考えてみると、TableAdapterの型付きデータテーブルに列を追加するようなことを想定されているようですので、そうであれば別名でプロパティを追加しても、それがデータテーブルの列の代わりになることはできません。すみません。少し私が勘違いしていたようです。
    さて、代替手段ですが、TableAdapterのDataTableにデザインから新しい列を追加し、その列のExpressionプロパティにSUBSTRING(hoge列, 1, 4) + '-' + SUBSTRING(hoge列, 5, 6)を設定されてみてはいかがでしょうか? こちらでテストしてみましたが、うまく動いているようです。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2010年8月22日 17:00
    モデレータ
  • ご回答ありがとうございます。

    列の追加ということまでは考えておらず、最終的には、以下のような動作が実現できればと考えています。

    1.表示は「-」を含む形で行う。
    2.登録は「-」を含まない形で行う
    3.入力中でも4ケタ入力後に「-」が挿入され、さらに6ケタ入力後に「-」を挿入する

    ということを行いたいと思います。

    1 と 2 を実現するには、やはりプロパティにて操作をする方法がよさそうに思えます。

    また、3 についてはvaridatingイベントを利用すれば実現できると思っています。

    ただ、partialクラスにてプロパティを作成しようと思ったのですが、まず、躓いてしまったのが処理を加えたいと考えている
    tableadapterを右クリックし、コードの表示をすると各種サンプルなどでは選択したtableadapter名のpartialクラスが
    表示されているのですが、私の場合は、なぜか「テーブル名+DataTable」というpartialクラスが作成されます。

    これ自体は正常な動作なのでしょうか。

    上記のような状態になるため、partialクラスで作成したものを利用する場合、サンプルを見る限りですとTableAdapterの
    インスタンスを作成することで利用可能になるように見受けられるのですが、私の場合は、インテリセンスにあらわれすら
    しません。

    現状では、何がいけないのかさっぱり分からない状態です。

    2010年8月23日 12:34
  • > 私の場合は、なぜか「テーブル名+DataTable」というpartialクラスが作成されます。
    > これ自体は正常な動作なのでしょうか。

    partial な DataSet クラスの中に、それが作成されていますよね?
    それは正常です。
    TableAdapter に追加されるわけではありませんので、そのインテリセンスには表示されません。

    項目のプロパティを追加される先としては、「テーブル名+Row」の partial になるかと思います。
    仮にテーブル名を「Table1」とすれば、「Table1Row」というクラスが存在しますので、それの partial クラスを「Table1DataTable」の partial の中に定義します。
    そうすると、そのプロパティ実装の中では、既存する他の項目プロパティを参照できますし、他の項目プロパティと同様に「Table1DataTable[0].MyColumnProperty」のように使用できます。

    > 現状では、何がいけないのかさっぱり分からない状態です。

    型付データセットのために自動生成されるコードってわかりづらいですからね。


    ここからは別の方法になります。

    > プロパティを用いて、「Get」の際に「-」を追加、「Set」の際に「-」を削除という処理を行って
    > いたのですが、

    そのような変換を行うメソッドをどこかに作成しておき、
    Binding の Format イベントや Parse イベント
    (DataGridView であれば CellFormatting イベントや CellParsing イベント)
    を利用して変換を行うという方法はいかがですか?
    (Parse の処理は Validating や DataTable の Changing 等でも行えますが、Binding としては Parse がこの目的として用意されたものになります。)

    具体的には、たとえばすでに型付データセットから自動作成した「詳細」形式のメンテナンス画面があり、その項目の1つが Field1 だとした場合、デザイナの自動生成コードでは TextBox の Text プロパティにはすでに Binding が設定済みとなっていますが、その Binding のイベントを以下のように割り当てます。
    以下の例ではハイフンの編集を各イベントハンドラ内で直接行っていますが、変換を行うメソッドを呼び出すようにすると、保守性が良くなると思います(以下の例ではエラーチェックは省略しています)。

    public Form1()
    {
        InitializeComponent();

        var bindingField1 = field1TextBox.DataBindings["Text"];
        bindingField1.Format += new ConvertEventHandler(bindingField1_Format);
        bindingField1.Parse += new ConvertEventHandler(bindingField1_Parse);
    }

    private void bindingField1_Format(object sender, ConvertEventArgs e)
    {
        // 1234567891 → 1234-567891
        e.Value = ((string)e.Value).Insert(4, "-");
    }

    private void bindingField1_Parse(object sender, ConvertEventArgs e)
    {
        // 1234-567891 → 1234567891
        e.Value = ((string)e.Value).Remove(4, 1);
    }


    追記:
    今気づいたんですが、言語もバージョンも間違ってましたので、訂正させてください。

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'TableAdapter.Fill する前にイベントハンドラを設定する。
        Dim bindingField1 As Binding = Field1TextBox.DataBindings("Text")
        AddHandler bindingField1.Format, AddressOf bindingField1_Format
        AddHandler bindingField1.Parse, AddressOf bindingField1_Parse
    End Sub

    Private Sub bindingField1_Format(ByVal sender As Object, ByVal e As ConvertEventArgs)
        '1234567891 → 1234-567891
        e.Value = DirectCast(e.Value, String).Insert(4, "-")
    End Sub

    Private Sub bindingField1_Parse(ByVal sender As Object, ByVal e As ConvertEventArgs)
        '1234-567891 → 1234567891
        e.Value = DirectCast(e.Value, String).Remove(4, 1)
    End Sub

    • 編集済み TH01 2010年8月25日 0:54 追記
    • 回答としてマーク TI-cb400 2010年8月27日 20:00
    2010年8月23日 13:10
  • おはようございます。

    なかなかお返事ができず、大変申し訳ございませんでした。

    TH01様にご提示いただいた方法で実現をすることができました。

    今回のことで、FormatとParseについて、ある程度理解することができました。

    本当に有難うございました。

    2010年8月27日 20:30