none
サブテーブルでのTimestamp値取得は、どうすればよいですか? RRS feed

  • 質問

  • Form:F_I_Sales(売上伝票) があります-- 対応するDBでのテーブルは、T_Sales です。

    このフォームF_I_Salesには、売上品目としてDataGridViewが表示され、売上伝票内の売上品目(売上詳細)
    を複数表示しています。 これに対応するDBテーブルは、T_SalesDetails です(サブテーブルと、仮に呼びます)。

    排他制御として、TimeStamp値をDBテーブル(T_Sales)に設け、これを利用して排他制御をしています。
    T_SalesDetails にも、TimeStamp列は設けてあります。 このサブテーブルからも、TimeStamp値を取得したいのですが、うまくいきません。

    良い方法があれば、教えてください。


    (1):サブテーブルが、Uniqueにメインテーブル(ここでは、T_Sales)に従属しているのなら、排他制御はT_Salesにだけ施せば十分で、この方法でうまく機能しています。


    (2):しかし、別のメインテーブルにも従属(関係)している場合を想定して考えてみました。
    つまり、他の(別種の)フォームからも、このT_SalesDetailsにアクセスするのなら、ここにも排他制御をかける必要が出てきます。

    (2)の場合がうまくいきません。
         T_SalesDetailsには、同じSales_ID(主キーです、売上伝票ID)を持つレコードが複数あります。
         Sales_ID と LineNo の二つがセットで主キーになっています。このセットで、Uniqueness取得です。
      ですから、T_SalesDetailsでTimeStamp値を取得する場合は、複数となります。
      この取得法が分からず困っています。 

      Update文のWhere条件で使用しますので、このTimeStamp値(TMSTP)は、Publicにしておく必要があります。 
       
        さしあたり、以下のようにして For Nextで取得を試みました(窮余の策?)。

            'F_I_Salesの中のDataGridView1の内容表示---T_SalesDetailsの中身
            Dim ds_SalesDetails = New DataSet
            Dim dt_SalesDetails As New DataTable  'DataGridView1のデータテーブル(DataSource)
            adapter.SelectCommand = SQL

                Dim SID As Integer
                SID = CInt(Me.TX_Sales_ID.Text) ’ID(主キー)です。

                Dim sb As New System.Text.StringBuilder
                sb.Append("SELECT T_SalesDetails.Sales_ID")
           sb.Append(" ,T_SalesDetails.[LineNo]") 
                ------------------略

                sb.Append(" , T_SalesDetails.TMSTP") ’TMSTPが、TimeStampです。

                sb.Append(" FROM T_SalesDetails")
                sb.Append(" WHERE T_SalesDetails.Sales_ID= " & SID & "")

                SQL.CommandText = sb.ToString()
                adapter.SelectCommand = SQL
                adapter.Fill(ds_SalesDetails)
                dt_SalesDetails = ds_SalesDetails.Tables(0)

                DataGridView1.DataSource = dt_SalesDetails

                Dim k As Integer
                k = Me.DataGridView1.Rows.Count
                For i = 0 To k - 1
                    'TimeStamp---Public Byte 1000個まで許容:排他制御 -- 'T_SalesDetails用
                    'TimeStamp値取得--データ更新毎にカウント記録(排他制御)--重要!

             ’以下の行がエラーになります!

                    TMSTP_Byte_Sub(i) = CType(DataGridView1.Rows(i).Cells("TMSTP").Value, Byte())
                Next

      上記はForm_Load内でのコードです。この段階でT_SalesDetailsで、おなじSales_IDを持つレコードが何行あるか   は不明(可変)ですので上記のようにしたのですが。

     
    (3) TMSTP_Byte_Sub(i)は、moduleで下記のように定義しました(Publicで)。
     
      下記コードは、エラーがでます。
      Public TMSTP_Byte_Sub(1000) As Byte() エラー(変数とその型の両方で、配列修飾子を指定することはできません。)
      
      で、次に下記のようにしました:
      Public TMSTP_Byte_Sub(1000) As Object
      で、上記コードにあるように、
        TMSTP_Byte_Sub(i) = CType(DataGridView1.Rows(i).Cells("TMSTP").Value, Byte())
      としましたが、エラーです。
      エラー内容:型 'System.Drawing.Bitmap' のオブジェクトを型 'System.Byte[]' にキャストできません。

       おそらく、DataGridView1.Rows(i).Cells("TMSTP").Valueがいけないような気がしています。

    (4)要するに、T_SalesDetailsのSales_IDに対応するレコード(複数個、LineNoに対応)のTimestamp値を取得したいのです(Publicで)。

    以上です、よろしくお願いします。

    YKsaila

     

    2012年12月14日 12:08

回答

  • サブテーブルでの排他制御(TimeStamp利用)は、下記のようにしました。これで、うまく動いています。
    サブの中には(DataGridView)、行の追加・削除・行番号揃がありますので、複雑さが数倍にもなり苦労しました。

    丸二日もかかりました!

    今のところ、テーブルがサブの場合、他のテーブルにも従属していることはなさそうなので、
    これは保存し必要が出たときに使用することにします。無駄なコード、不要なコードは避けるべきですから。
    でも、いつか出てきそうな気がします。あるテーブルが、複数のフォーム・テーブルに関係していることは十分にありそうですから。

    売上詳細(品目)は、サーバー(DBテーブル)→DataTable → DataGridViewと表示されます。
    当初は、つい、目に見えている表(DataGridview)でTimeStampを使用しようとしました。
    良く考えれば、その元のDataTableから取得すれば良かったのです。下記(A)参照。


    以下、関係コードその他:
    1.Moduleで定義

     '排他制御用:TimeStamp値(TMSTP)
     Public TMSTP_Byte As Byte()  'メインテーブル用
     Public TMSTP_Byte_Sub(1000) As Object 'SubForm(サブテーブル)用:最大行数=1,000

    (A):Form_Load 時、サブテーブル用にTMSTP(TimeStamp)値の初期値を保存する---TMSTP_Byte_Sub(i)
     (DataGridViewで行の追加・削除・行揃実行→T_SalesDetailsにUPdate → TMSTP値更新される。初期値でなくなるので、その都度取得が必要。)
            Dim k As Integer
            k = dt_SalesDetails.Rows.Count  'dt_SalesDetails:データテーブル(DBテーブルの、T_SalesDetailsに対応するもの)
             For i = 0 To k - 1
                'TimeStamp---Public Byte 1000個まで許容:排他制御 -- 'T_SalesDetails用
                TMSTP_Byte_Sub(i) = CType(dt_SalesDetails.Rows(i).Item("TMSTP"), Byte())
             Next

    (B): Update時の注意事項(メインフォーム内で修正ボタンを押したとき)
     ①サブテーブルから先:TimeStamp値(TMSTP)使用---T_SalesDetails → TMSTP_Byte_Sub(i)
     ②メインテーブル:TimeStamp値(TMSTP)使用---T_Sales → TMSTP_Byte

    サブテーブルの排他処理をメインの後にすると、他のメインテーブルからサブテーブルにアクセスがあった時に問題が発生する。
    例えば削除時、メインは消えるが、他からアクセスされたサブだけは残る。 これを防ぐには、サブを先にする。

    (C):行追加の場合(行削除、行番号揃えも、これと同様)
    ① 排他チェック;フォームを開いている間に、他からのアクセスがある。
         k = Me.DataGridView1.Rows.Count
          '他のメインテーブルからアクセスがあった時への対処だから、最少限のUpdate量でよい(ここでは、IDのみのUpdate)
            For i = 0 To k - 1
                    J = CInt(Me.DataGridView1.Rows(i).Cells("LineNo").Value)  'LineNoは書き込み不可
                    SQLst = "Update T_SalesDetails Set Sales_ID=@Sales_ID FROM T_SalesDetails " _
                        & "WHERE T_SalesDetails.Sales_ID= @Sales_ID and T_SalesDetails.[LineNo]= " & J & " and TMSTP= @TMSTPSub "
                    Dim sqldgr0 As New System.Data.SqlClient.SqlCommand(SQLst, Con)
                    sqldgr0.Parameters.AddWithValue("@Sales_ID", CInt(Me.TX_Sales_ID.Text))
                    sqldgr0.Parameters.AddWithValue("@TMSTPSub", TMSTP_Byte_Sub(i))
                    'sqldgr0.ExecuteNonQuery()
                    Dim n2 As Integer
                    n2 = sqldgr0.ExecuteNonQuery()
                    If n2 = 0 Then
                        MessageBox.Show("行追加できません!  他のPCで使用されました、再試行してください。" _
                                        & vbCrLf & "( 他データへ移行し、戻れば再試行できます。 )")
                        Con.Close()
                        sqldgr0.Dispose()
                        adapter.Dispose()
                        Con.Dispose()
                        Exit Sub
                    End If
            Next


    ② 行追加:INSERT、この段階で行を追加する。
    ③ Update---Where条件にTMSTP(TimeStamp)無し(現内容の書き込みだから、不要)
    ④ Select --- datatable(TMSTPあり)=dt_SalesDetails

    ⑤  '行追加=Update(③)したので、ここで、新規のTMSTP_Byte_Sub(i)取得する(行追加=Updateしたので、Timestamp値が変更されている)。
        '変更されたTMSTP値保存--Form_Load時の値とは異なる!(DataGridViewでの行追加・削除・行揃でT_SalesDetailsにUpdateするから)。
      'TMSTP_Byte_Sub(i) は、Publicなので他で有効に使用できる。 
         Dim m As Integer
         m = dt_SalesDetails.Rows.Count
         For i = 0 To m - 1
             'TimeStamp---Public Byte 1000個まで許容:排他制御 -- 'T_SalesDetails用
             TMSTP_Byte_Sub(i) = CType(dt_SalesDetails.Rows(i).Item("TMSTP"), Byte())  
         Next


    • 編集済み yksaila 2012年12月19日 0:05
    • 回答としてマーク yksaila 2012年12月19日 0:05
    2012年12月19日 0:02

すべての返信

  • データベース以前の問題で、配列、Byte[]の使い方がわかっていないのでは?

    またこのエラーメッセージを質問者さんは読んだのですか?

    エラー内容:型 'System.Drawing.Bitmap' のオブジェクトを型 'System.Byte[]' にキャストできません。

    なぜエラーメッセージにBitmapが出てくるのでしょうか。

    • 回答の候補に設定 Jitta 2012年12月19日 14:06
    2012年12月14日 12:55
  • >データベース以前の問題で、配列、Byte[]の使い方がわかっていないのでは?

    そうだと思います。

    >またこのエラーメッセージを質問者さんは読んだのですか?

    読みました。 エラー内容も読みました。

    >なぜエラーメッセージにBitmapが出てくるのでしょうか。

    DataGridViewの仕様から来るのでしょうか?

    やる気はあるのですが、経験・知識不足なのです。 ヒントなり、学習の道筋なり教えていただければ幸いです。

    YKsaila

    2012年12月14日 13:31
  •  なにがわからないのか、わかりません。

    「(2)の場合がうまくいきません。」とのことですが、どのような SQL 文を書いて、どのような返答を期待したところ、実際にはどのようなものが返ってきたのでしょうか。この3つの「どのような」を明らかにしないと、「うまくいきません」だけでは何もアドバイスできないです。

    「ですから、T_SalesDetailsでTimeStamp値を取得する場合は、複数となります。」・・・だから、どのような返答を期待して、どのような SQL を書いたのでしょうか。2つのテーブルから、同じ名称のカラムを取得するのでしょうか。AS で別名をつけられますが、そういうことではなく?
    このことと、「おそらく、DataGridView1.Rows(i).Cells("TMSTP").Valueがいけないような気がしています。」がつながりませんね。何を、どのように判断して、このように推測されたのでしょうか。おそらく「判断の仕方」を間違っているので、直すところを間違い、正しい修正が出来ないのだと思います。TMSTP がタイムスタンプで、これが間違いと関係しているなら、エラーメッセージに「型 'System.Drawing.Bitmap' のオブジェクトを」は出てこないです。別のところに間違いがあります。

    「ヒントなり、学習の道筋なり教えていただければ幸いです。」・・・だったら、「なぜ」を書きましょう。なぜ、そのようにコーディングしたのか。なぜ、そのように判断したのか。考えた道筋がわかれば、どこで間違ったのか、どのように考えるべきなのか、示すことが出来ます。

    yksailaさんって、SQL Injection の質問もされていませんでしたっけ?そうだとすると、「sb.Append(" WHERE T_SalesDetails.Sales_ID= " & SID & "")」は、いただけないですよね。あと、StringBuilder.AppendFormat メソッドも要チェックですよ。


    Jitta@わんくま同盟

    2012年12月14日 14:18
  • >「(2)の場合がうまくいきません。」とのことですが---

    この後に書いてある文を、読んでいただければ十分に理解していただけるのではないでしょうか?

    エラー箇所も指摘しています。 

    T_SalesDetailsからのTimeStamp取得ですが;

    Datatableに一旦もってきてそこからtimeStamp値を取得するのが簡単と思ったのですが、Sales_IDとLineNoでTimeStampは一意に取得できますから、その方法も今考えています。

    >「sb.Append(" WHERE T_SalesDetails.Sales_ID= " & SID & "")」は、いただけないですよね。

    すいません、これは分かっていて書いています。 本式コードでは、パラメタライズドクエリにしています、面倒なのでそのままにしたのです。

    最初は、ここのSIDですが、テキストボックスは.enabled=false なので、このままでもいいかな?、と思ったのも事実です。

    でも、やはり修正しておこうと考えなおし、修正しました。

    (テキストボックスが入力不可なら、上記のままでもいいのでしょうか? 私は、そう考えたのですが)

    YKsaila

    2012年12月14日 15:06
  • 下記のように、して見ました。

    こうしましたら、エラー表示もなく、修正書き込みも出来ました。 普通に動いています。

    ただ、Timestamp値が正しくサブテーブルで使用されているかの点検が必要です。

    とくに、DataGridViewの行の追加・削除・行番号揃えをした時に、正常動作しているか(排他制御が正常か)の点検が必要です。

    これは、明日からやります。 うまくいっていると、いいのですが。 どこかに、まだ誤りがある気もしますが?

    以下、コードです;

    1.Moduleで定義

     '排他制御用:TimeStamp値
     Public TMSTP_Byte As Byte()   'Main Table用(通常のフォーム)
     Public TMSTP_Byte_Sub(1000) As Object   'SubForm(SubTable)用--DataGridview対応

    2.Form_Loadで;
     Dim k As Integer
     k = dt_SalesDetails.Rows.Count ’dt_SalesDetailsは、DBテーブル(T_SalesDetails)に対応するデータテーブル
           For i = 0 To k - 1
              'TimeStamp---Public Byte 1000個まで許容:排他制御 -- 'T_SalesDetails用
              'TimeStamp値取得--データ更新毎にカウント記録(排他制御)--重要!
              TMSTP_Byte_Sub(i) = CType(dt_SalesDetails.Rows(i).Item("TMSTP"), Byte())
           Next

    YKsaila

    2012年12月14日 15:49
  • 何をされたいのかはおそらく理解できます。要するに、T_SalesDetailsの各行のTimeStamp値を配列にしまっておき、Update文発行時にそれを利用したいように見えます。
    しかし、このようなコードを書くことはほとんどありません。コード量が多くなりますので見通しが悪く、保守性を欠き、やっかいなバグの温床になりかねません。お勧めはTableAdapterを使用することです。同時実行制御をノーコーディングで実現できます。SurferOnWwwさんも書かれていましたが、自動生成されたTableAdapterクラスのコードを読むことも簡単にできますので、どのようなコードが生成されたかを見ることは勉強になります。そのコードこそがYKsailaさんがこれからご自分で書こうとされているコードだと思います。
    プログラムの上達の早道は、良いコードをたくさん読むことです。良いコードこそが一番の先生であり、それを完全に理解したのであれば、初心者から一歩前に進めます。ただ、前提となる知識が無いと完全に理解するのは無理でしょう。完全に理解できないからといってがっかりしないで下さい。理解できないところは聞いてください。少し高い本ですが、お薦めは「プログラミングMicrosoft ADO.NET」という本を読まれることです。今は、「プログラミングMicrosoft ADO.NET2.0」になっていますが、こちらを私は読んでいないので何とも言えないのですが、おそらくこちらは大幅にページ数が増えており、追記が主だと思いますので、こちらがおすすめじゃないかと思います。

    なぜ、このような本を薦めているかと言いますと、このまま今回掲載されたコードのまま進めますと、おそらくかなりの説明が必要になると思われるからです。それは基本的なADO.NETの知識が不足しているのではないかと思うからです。
    例えばTimeStamp列の値を配列で保持する必要はありません。データテーブル上に保持していれば十分です。また、データテーブルの行はバージョン管理されています。例えば同じ一行に、一番最初に取得した値、ユーザーがそこに書き込んだ値などを同時に保持しています。何も指定しなければユーザーが書き込んだ値が取り出されるようになっています。この辺りから説明することになります。私は説明することはどちらかというと好きな方ですので苦にはなりませんが、フォーラムでのやり取りでは時間がかかりますし、どうてしても質問に対する回答だと体系立って説明することが難しくなります。私が一方的に体系立って講義すれば別でしょうが、それはこのフォーラムには沿いません。ですから、体系立って説明してある書籍をお薦めしているのです。
    この書籍には、どのように同時実行制御を行うか、マスターおよびその詳細テーブルをどのように更新するかといったことが書かれていますので、本当に力になると思います。
    回答をするのが面倒で書籍を薦めているわけではありませんし、書籍を読んでもどう書いてよいかわからないということもあるかと思いますので、その時は忌憚なく質問されると良いと思います。今回はTableAdapterを使う・使わない、書籍を読む・読まれないもYKsailaさんの自由な選択ですので、以上を踏まえた上で、どのような方向に進んで行かれたいのか、一度お聞かせ下さい。


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

    2012年12月14日 16:59
    モデレータ
  • この後に書いてある文を、読んでいただければ十分に理解していただけるのではないでしょうか?

     書いてあることは理解しましたが、あなたの意図通りに理解できたかどうかは、わかりません。私には、ここに書いてある文からあなたの意図をくみ取ることは出来ませんでした。私の理解を述べます。


    (2):しかし、別のメインテーブルにも従属(関係)している場合を想定して考えてみました。
    つまり、他の(別種の)フォームからも、このT_SalesDetailsにアクセスするのなら、ここにも排他制御をかける必要が出てきます。

     ここのつながりがわかりません。「別のメインテーブル」と「他の(別種の)フォーム」が、なぜ「つまり」で繋がるのでしょうか。データベース上に定義されたテーブルと、アプリケーションで作成するフォームが1:1で対応しているような印象を受けますが、そんなことは無いはずなので、意味がわかりません。(アプリケーションの仕様としては1:1で対応しているかもしれませんが、コードは、そんなこととはお構いなしに作れます。)

     まず、「見せるためのもの」と、「ビジネスとして必要なロジック」を、分けて考えましょう。「このフォームでこれこれをする」ではなく、「この様な要求をこの様に処理する」のように、考え方を変えます。ここで、「この様に」には、見せ方を含みません。今回なら、「売り上げ詳細を提供するために売上伝票を参照する」でしょうか。これに対して「売り上げ詳細を要求する」という要求があります。しかし、この要求が「見る」ために発生したのか、「他へ知らせる」ために発生したのかはわかりません。見るために発生したのならフォームなどが出てきますが、他に知らせるならネットワークなどの通信が出てきます。ですから、フォームとは結びつけないように考えます。

     また、文章の中に断片的なコード(この場合はフォームの変数名やテーブル名)が混ざると、非常に読みづらいです。

    T_SalesDetailsには、同じSales_ID(主キーです、売上伝票ID)を持つレコードが複数あります。Sales_ID と LineNo の二つがセットで主キーになっています。このセットで、Uniqueness取得です。ですから、T_SalesDetailsでTimeStamp値を取得する場合は、複数となります。

     「ですから」が、その前とどう繋がっているのか、わかりません。
    ・売り上げ詳細テーブルには、同じ伝票 ID を持つレコードが複数ある。
    ・売り上げ詳細テーブルの主キーは、伝票 ID と項番のセットである。
    ・ですから、売り上げ詳細テーブルでタイムスタンプ値を取得する場合、複数となる。
    ………どうでしょうか?1項目2項目から、3項目に繋がりますか?私にはつながりが無い様に思います。1つのテーブルから複数のレコードを引っ張ってくると、複数の値が取得できるのは当然です。そのように取得したのですから。そのようにしているのに、何が困るのか、わかりません。

     タイムスタンプが重要なのは、1レコードに対して、です。複数レコードで1つのタイムスタンプを持つわけではありません。1レコード取得すると複数のタイムスタンプ フィールドがあるというのなら、なるほど「ですから、複数となる」と言えますが、そのような状態なのでしょうか。そうだとすると、一般的な作り方からは、考えられない作りなのですが。

    Update文のWhere条件で使用しますので、このTimeStamp値(TMSTP)は、Publicにしておく必要があります。

     これもわかりません。更新クエリの条件に使用することと、「Public にしておく」ことが、どの様に関連するのでしょうか。そもそも、「Public にしておく」とは、何を意味しているのでしょうか。何かのクラスでタイムスタンプを保持するメンバーをパブリックにするという意図でしょうか。そうだとしても、そのことと、SQL 文の条件に指定するということが何故関係するのか、わかりません。

     おそらく、インスタンスを渡して、クラス外から値を参照しようとしているのでしょうか。そうだとすると、カプセル化に失敗しています。外からは「条件をくれ」とメッセージを投げ、クラス内で条件を作成し、条件の詳細は隠して渡すようにした方が良いと思います。(もちろん、「タイムスタンプをくれ」という要求を否定するものではありません)

     コードは見ていません。コードを読むのはコストがかかります。何をしようとしているかわからないコードを読むのは、さらにコストがかかります。先の投稿をしたときは、かなり酔っていたので、それだけのコストをかける余裕がありませんでしたし、白面の今回も、それだけのコストをかけようとは思えません。

     バグというのは、プログラムに実行させたいことと、コードに書いてあることが異なっている状態を言います。上記のように、プログラムに実行させたいことがわからない状態なのにコードを読んで、何がわかるのでしょうか?

    エラー内容:型 'System.Drawing.Bitmap' のオブジェクトを型 'System.Byte[]' にキャストできません。

     質問本文の肝は、ここだと思っています。そこで、タイムスタンプについての質問だとタイトルで入っているのに、なぜ Bitmap が出てくるのかわかりません。タイトルと質問本文、どちらかが間違っているのでしょうが、どちらが間違っているのか、私には判別できません。


    Jitta@わんくま同盟

    2012年12月15日 12:48
  • サブテーブルでの排他制御(TimeStamp利用)は、下記のようにしました。これで、うまく動いています。
    サブの中には(DataGridView)、行の追加・削除・行番号揃がありますので、複雑さが数倍にもなり苦労しました。

    丸二日もかかりました!

    今のところ、テーブルがサブの場合、他のテーブルにも従属していることはなさそうなので、
    これは保存し必要が出たときに使用することにします。無駄なコード、不要なコードは避けるべきですから。
    でも、いつか出てきそうな気がします。あるテーブルが、複数のフォーム・テーブルに関係していることは十分にありそうですから。

    売上詳細(品目)は、サーバー(DBテーブル)→DataTable → DataGridViewと表示されます。
    当初は、つい、目に見えている表(DataGridview)でTimeStampを使用しようとしました。
    良く考えれば、その元のDataTableから取得すれば良かったのです。下記(A)参照。


    以下、関係コードその他:
    1.Moduleで定義

     '排他制御用:TimeStamp値(TMSTP)
     Public TMSTP_Byte As Byte()  'メインテーブル用
     Public TMSTP_Byte_Sub(1000) As Object 'SubForm(サブテーブル)用:最大行数=1,000

    (A):Form_Load 時、サブテーブル用にTMSTP(TimeStamp)値の初期値を保存する---TMSTP_Byte_Sub(i)
     (DataGridViewで行の追加・削除・行揃実行→T_SalesDetailsにUPdate → TMSTP値更新される。初期値でなくなるので、その都度取得が必要。)
            Dim k As Integer
            k = dt_SalesDetails.Rows.Count  'dt_SalesDetails:データテーブル(DBテーブルの、T_SalesDetailsに対応するもの)
             For i = 0 To k - 1
                'TimeStamp---Public Byte 1000個まで許容:排他制御 -- 'T_SalesDetails用
                TMSTP_Byte_Sub(i) = CType(dt_SalesDetails.Rows(i).Item("TMSTP"), Byte())
             Next

    (B): Update時の注意事項(メインフォーム内で修正ボタンを押したとき)
     ①サブテーブルから先:TimeStamp値(TMSTP)使用---T_SalesDetails → TMSTP_Byte_Sub(i)
     ②メインテーブル:TimeStamp値(TMSTP)使用---T_Sales → TMSTP_Byte

    サブテーブルの排他処理をメインの後にすると、他のメインテーブルからサブテーブルにアクセスがあった時に問題が発生する。
    例えば削除時、メインは消えるが、他からアクセスされたサブだけは残る。 これを防ぐには、サブを先にする。

    (C):行追加の場合(行削除、行番号揃えも、これと同様)
    ① 排他チェック;フォームを開いている間に、他からのアクセスがある。
         k = Me.DataGridView1.Rows.Count
          '他のメインテーブルからアクセスがあった時への対処だから、最少限のUpdate量でよい(ここでは、IDのみのUpdate)
            For i = 0 To k - 1
                    J = CInt(Me.DataGridView1.Rows(i).Cells("LineNo").Value)  'LineNoは書き込み不可
                    SQLst = "Update T_SalesDetails Set Sales_ID=@Sales_ID FROM T_SalesDetails " _
                        & "WHERE T_SalesDetails.Sales_ID= @Sales_ID and T_SalesDetails.[LineNo]= " & J & " and TMSTP= @TMSTPSub "
                    Dim sqldgr0 As New System.Data.SqlClient.SqlCommand(SQLst, Con)
                    sqldgr0.Parameters.AddWithValue("@Sales_ID", CInt(Me.TX_Sales_ID.Text))
                    sqldgr0.Parameters.AddWithValue("@TMSTPSub", TMSTP_Byte_Sub(i))
                    'sqldgr0.ExecuteNonQuery()
                    Dim n2 As Integer
                    n2 = sqldgr0.ExecuteNonQuery()
                    If n2 = 0 Then
                        MessageBox.Show("行追加できません!  他のPCで使用されました、再試行してください。" _
                                        & vbCrLf & "( 他データへ移行し、戻れば再試行できます。 )")
                        Con.Close()
                        sqldgr0.Dispose()
                        adapter.Dispose()
                        Con.Dispose()
                        Exit Sub
                    End If
            Next


    ② 行追加:INSERT、この段階で行を追加する。
    ③ Update---Where条件にTMSTP(TimeStamp)無し(現内容の書き込みだから、不要)
    ④ Select --- datatable(TMSTPあり)=dt_SalesDetails

    ⑤  '行追加=Update(③)したので、ここで、新規のTMSTP_Byte_Sub(i)取得する(行追加=Updateしたので、Timestamp値が変更されている)。
        '変更されたTMSTP値保存--Form_Load時の値とは異なる!(DataGridViewでの行追加・削除・行揃でT_SalesDetailsにUpdateするから)。
      'TMSTP_Byte_Sub(i) は、Publicなので他で有効に使用できる。 
         Dim m As Integer
         m = dt_SalesDetails.Rows.Count
         For i = 0 To m - 1
             'TimeStamp---Public Byte 1000個まで許容:排他制御 -- 'T_SalesDetails用
             TMSTP_Byte_Sub(i) = CType(dt_SalesDetails.Rows(i).Item("TMSTP"), Byte())  
         Next


    • 編集済み yksaila 2012年12月19日 0:05
    • 回答としてマーク yksaila 2012年12月19日 0:05
    2012年12月19日 0:02
  • trapemiyaさんへ

    いつも、親切な回答、ありがとうございます。

    自分なりの解決策をアップした後で、trapemiyaさんの書き込みを読みました。

    もちろん、tableadapterも使いたいし、書籍も購入します。 何事も完全に理解して進めるのが、信念です。

    それに、知らなかったことを理解することは、本当に楽しいことです。 粘り強さと考える力には少し自信がありますので、何とかやっていけると思います。 よろしく、お願いします。

    プログラミングMicrosoft ADO.NET2.0 を購入すれば良いのですね、早速手配します。 

    読んでいて、どうしても不明な点がでましたら、質問いたしますので、その時はよろしくお願いします。

    他にも、私が読むべき本がありましたら、ご紹介ください。 しばらくは、上記の本で手一杯でしょうが。

    YKsaila

    2012年12月19日 0:22
  • Jittaさんへ

    おっしゃっていることは理解できます。 その通りかも知れません

    だいたい、私個人が必死に考えていることを、第三者に理解していただくように書くことは難しいですね。 

    それに、本人自身の頭の整理がついていない状態ですと、なおさらです! 

    この件では、皆さんに余分の集中を強いたみたいで、申し訳ありません。 

    二日ほど考え、少し頭の整理がつきました。 どうしても解決できず、そのままソファで寝てしまったことも数度あります。

    ま、これが、楽しいと言えば楽しいことかも? 後から言えば、ですが。

    ここの書き込みで、私が知りたかったことは、サブテーブルから複数のTimeStamp値を取得する方法でした。

    サブテーブルには、一個のID(Sales_ID)に対して複数の項目(LineNo)があります。 一個の売上伝票に記載された複数の売上品目(詳細)です。 これに、LineNoが対応しています。 ですから、TimeStampが複数というのは、このLineNoに対応するもので、これ自体は一対一対応です。

    datatableからFor --Nextで取得出来ました。 これを知りたかったのです。

    当初は、dataGridviewから取得を試みたのですが、その元のdatatableから取ればよかったのです。

    どうしても、目に見えているものに引かれますので、DatagridViewに向かってしまったみたいです。 DataGridViewは、描画機能とか細部で使っているのか(良く分かりませんが)、複雑なところがありますね。 だから失敗して、Bitmapとかのエラー表示が出たのかもしれません。 DataGridViewからの方法もあるかもしれませんが、元データのdatatableから取得できたわけですから、DataGridViewはここでは考える必要はないですね。

    私の解決策もアップしておきました。 よろしければ、お読みください。

    YKsaila


    • 編集済み yksaila 2012年12月19日 1:14
    2012年12月19日 0:50
  • もちろん、tableadapterも使いたいし、書籍も購入します。 何事も完全に理解して進めるのが、信念です。

    それに、知らなかったことを理解することは、本当に楽しいことです。 粘り強さと考える力には少し自信がありますので、何とかやっていけると思います。 よろしく、お願いします。

    私と基本的に同じ部類の人ですね(笑) 少し先走ってお話しをすると、TableAdapterは非常に便利で、私も頻繁に使用します。ただ、どうしてもTableAdapterはウィザードによってVisual Studioが自動的に書いてくれたクラスですから、不満な点や足らないところがあります。それを補うためにパーシャルクラスやパーシャルメソッドを利用するのですが、その際にADO.NETの知識が非常に役に立ちます。
    逆に言えば、この知識があるからこそ、パーシャルクラスやパーシャルメソッドで拡張し、いろいろな工夫ができるようになるのです。
    この知識を得ることにおいて、私は先に紹介した書籍が非常に役に立ちました。ADO.NETに関する書籍は、私はこの書籍しか読んでいませんので、他のお勧めの書籍は残念ながら紹介することはできませんが、少なくともこの書籍は良書だと思います。

    以上のように、現在でもADO.NETに関する深い知識は依然として重要だと思います。この先、その勉強を進められる上で、何かわからないことがあれば、また聞いて下さい。私も一緒になって勉強して解決方法を探るかもしれませんが、それはまたそれで好きなことであり、全く苦になりませんので、大丈夫です。


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

    2012年12月19日 3:00
    モデレータ
  •  やはり、何をしたくて、何を調べてどんな結果を得、それをどのように解釈して、このような設計になったのか、わかりません。何故このようなコードを書かなければならないのか、わかりません。

     今の実装では、DataGridView の表示順序と、TMSTP_Byte_Sub 配列のインデックスが等しくなければなりません。では、「登録した順序と表示されている順序が違う。登録した順序に並べて欲しい。」「金額の順次並べ替えられるようにして欲しい。」「明細のアイウエオ順(コード順)に並べ替えられるようにして欲しい。」「明細の、この行とこの行の間に新しい明細を挿入したい。」という要望に、対応できますか?今の実装では、DataGridView に表示されている順序と、タイムスタンプ配列のインデックスが等しくなければ、タイムスタンプがタイムスタンプの意味をなしません。「良く考えれば、その元のDataTableから取得すれば良かったのです」と書かれているとおり、その元の DataTable の値をそのまま使うようにしてください。


    Jitta@わんくま同盟

    2012年12月20日 13:18
  • Jittaさんへ

    >「良く考えれば、その元のDataTableから取得すれば良かったのです」と書かれているとおり、その元の DataTable の値をそ>のまま使うようにしてください。

    上記のようにしました。

    ご指摘の各要望に応えられるように準備はしてあります。 表示順・行削除・行挿入機能は当初から設定済みであり、これをTimeStamp値が一致するようにするのが目的でした。

    金額順・明細アイウエオ順は、売上詳細の実務ではあまり起きそうにないですが、必要が生じたときにはすでにあるもので対応すれば可能ですね。 実験は、十数回していますので、TimeStamp値の対応はOKのようです。

    ご指摘、有難うございました。

    YKsaila

    2013年1月6日 1:59