none
オプティミスティック同時実行コントロールエラー RRS feed

  • 質問

  • 現在SQLを用いてデータベースを作成しているのですが,必ずというわけではないのですがクエリを編集し,確定すると『結果ペインが最後に取得されてからデータが変更されています。変更を保存しますか?』というメッセージボックスがでて、『はい』を選択すると『更新された行はありません』となり,クエリが編集できません。

    すべてのクエリがそのような状況になっているわけではなく,TableAdapterから同時実行制御をoffにしても改善しませんでした。

    どのような対処法があるのでしょうか?よろしくお願いします。

    2010年10月2日 2:53

回答

  • テーブルは必ず行を一意に特定できるようにデザインされていなければなりません。行を一意に特定できないようにデザインすることもできてしまいますが、それは動かないプログラムを作成するのと同じことです。もし、列『出身地』という1つの列しか無いテーブルがあり、この列の値がユニークでないことを許すのであれば(同じ値が入ることを許すのであれば)、以下のようなデータが存在する時に一つの行を特定することができず、一つの行のみを変更することができません。

      会員テーブル

             『出身地』
    1レコード目  埼玉県
    2レコード目  埼玉県
    3レコード目  埼玉県

    2レコード目を東京都に変更したい。

    update 会員テーブル set 出身地 = '東京都' where ???

    2行目を特定するwhere句を書きようが無い。

    そのため、行を特定できる主キーと呼ばれる列を付加します。主キーの付け方もいろいろありますが、ここでは単に連番を保持する列『ID』を追加します。そうすると会員テーブルは以下のようになります。

      会員テーブル

             『ID』  『出身地』  
    1レコード目   1    埼玉県
    2レコード目   2    埼玉県
    3レコード目   3    埼玉県

    このようにすると2行目のみ変更したい場合、以下のようなSQLが書けます。

    update 会員テーブル set 出身地 = '東京都' where ID = 2

    さて、テーブルの設計がきちんとできることがアプリケーションの善し悪しに係わってきます。以下などが参考になりますので、目を通されることをお勧めします。上述した主キーの説明もあります。

    すぐわかるデータベースの基礎---目次
    http://itpro.nikkeibp.co.jp/article/COLUMN/20061208/256458/?ST=system

     

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    • 回答としてマーク -BALALAIKA- 2010年10月11日 6:10
    2010年10月8日 23:10
    モデレータ

すべての返信

  • クエリを編集する前に取得したデータがVisual Studio上で表示されていたりどこかに保存されていませんか?

    また、他の人や質問者さんが別アプリなどでそのテーブルを突っついていたりしませんか?

     

    2010年10月2日 4:31
  • 基本的にBasic上でのクエリ編集(追加・削除)はしていません。単純にクエリにデータを手打ちして,それをプログラム上で取得しているという形式です…

    そのデータ記入の際に入力後行変更しようとするとエラーがでます。

    別アプリでテーブルをいじるということもありません。

     

    わかりにくくてすいません。。。

    2010年10月2日 4:50
  • Updateするまえに、同じCommandオブジェクトに対してCommandTextを変えている、とかそういった状況ですか?

    すいません、再現手順がよく理解できていませんm(_ _)m
    具体的な手順やソースがわかると、より的確な答えがつくと思います。

    2010年10月2日 5:06
  • すいません。。。何分素人なもので。。。

     

    データベース自体は独立しています。プログラム内ではデータベース内の単語をRowを用いて階層を落として取得しているというだけです。

    プログラム内で編集は一切行いません。

    ソースは

    Dim con As New SqlClient.SqlConnection
        Using con
    '---<< 接続文字列の設定>>---
         con.ConnectionString = _
         "Data Source=.\SQLEXPRESS;" & _
         "AttachDbFilename=" & _
         """C:\Documents and Settings\uo.ht\My Documents" & _
         "\Visual Studio 2008\Projects\TEST0826\TEST0826\Database1.mdf"";" & _
         "Integrated Security=True;" & _
         "Connect Timeout=30;" & _
         "User Instance=True"

       con.Open()

       ds1 = New DataSet 
       Dim sql1 As String
       sql1 = "SELECT a FROM b WHERE doshiname='d'"
       adapter = New SqlClient.SqlDataAdapter()
       adapter.SelectCommand = New SqlClient.SqlCommand(sql1, con)
       adapter.SelectCommand.CommandType = CommandType.Text

    adapter.Fill(ds1)
    Me.TextBox2.Text = ds1.Tables(0).Rows(0)(0)

    を条件(SQLコマンド,変数)を変更して繰り返しているだけです。

    クエリは単に『単語の整理』の為に利用しているので、クエリへの記入は全部手動で必要な単語を登録している、といった形になります。

     

    同テーブル内で二つのクエリを利用しているのですが、片方のクエリではこのエラーは出ていません。

     

    非常に拙い文章ですが,申し訳ありません。。。

     

     

     

    2010年10月2日 5:24
  • そのクエリに問題があるように思います。問題が再現する最低限のクエリを支障が無い範囲でご提示されるとよいと思います。


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

    ここの文章には画像がアップロードできないようなので・・・

    http://www.imagecheese.com/gallery/ypyypy.jpg

     

    現在はテストプラグラムのためのサンプルデータベースを作成している所です。内容も非常に少なく、nullがほとんどです。

    上のクエリではエラーが起きないのですが,下のクエリでは先述のエラーが発生している状況です。

    2010年10月3日 14:58
  • クエリのコードに問題があるように思うのですが、クエリのコード自体はどうなっているのでしょうか?


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2010年10月4日 0:12
    モデレータ
  • クエリのコード,というとクエリを作成した際に表示される SELECT~といったものでしょうか…?

     

    一応,全く同じ内容でテーブルを作り直した場合には赤○に白抜きの!マークが表示されるため「SQLの実行」を行うと同じエラーが出ました。

     

     

     

     

    2010年10月5日 5:11
  • あっ、Visual Studioのサーバーエクスプローラーから「データの取得」で開く際のクエリってことですね? ひょっとしてデーターベースはmdbでしょうか?
    でれば、そのテーブルとのやり取りでデータに何らかの欠落が生じ、同時実行制御違反となっているのかもしれません。別のケースですが、過去にOleDb.OleDbType.DBDateを使用したために日付以外が切り捨てられて同時実行制御違反が発生したことがありました。うまく行かないテーブルに、うまく行くテーブルには無い型があれば、それが解決の糸口になるかもしれません。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2010年10月5日 5:58
    モデレータ
  • mdbではなくmdfです。

    型はすべてncharで統一しています。

    ちなみにテーブルを削除して新しいテーブルを作成し,同じ情報を入力しても起こりました、と書きましたが、

    その際にTebleの番号が3,4,5・・・と引き継ぎされていました。

    以前の情報が残ってしまっているのでしょうか・・・?

    2010年10月5日 6:18
  • 失礼しました。接続文字列に書かれていましたね。SQL Server Express Editionをお使いのようですが、こちらで再現できないので想像しながら書いています。
    まず、Table番号の引き継ぎですが、それはテーブル名を順番に採番しているだけですから問題ありません。
    次にエラーの発生する状況がよくわからずこちらで再現できません。以下の状況でよろしいでしょうか?

    1.Visual Studioのサーバーエクスプローラー(もしくはデーターベースエクスプローラー)でSQL Server Expressに接続する。

    2.そこに表示されるテーブルの値を直接手で変更し、保存しようとすると同時実行制御違反が発生する。

    ただ、これだけの手順だと通常は同時実行制御違反は発生しないのですが・・・。同時実行制御違反が発生するケースは、サーバーエクスプローラーでテーブルを開いてデータを表示した後に、どこかそことは違う場所でそのデータが変更された場合が一般的ですが、そのようなことは発生していないのでしょうか?


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2010年10月5日 7:00
    モデレータ
  • 「違う場所」というと,プログラム内等で、ということでしょうか・・・?

    そのようなプログラムは組んでいないです。

    思い当たる節としては、

    1.変更を頻繁に行っていた

    2.テーブルデータ以外にテーブル定義の変更・保存も行っていた(行き当たりばったりでテーブルの値を変更していたので,新しいテーブル定義が必要になったため)

     

    もし1,2が原因であるとすれば新しくテーブルを作って値を入力すれば直ると思っていたのですが・・

     

    2010年10月5日 7:39
  • 「違う場所」というと,プログラム内等で、ということでしょうか・・・?

    プログラムとは限りません。自分があるデータを読み込み、そのデータを変更して保存しようとした時に、最初に読み込んだデータが誰かに変更されていたため、このまま変更を保存すると誰かが変更した内容が失われてしまうので、その場合に発生するのが同時実行制御違反です。

    1.Aさんがあるレコードを読み込んだ。列は名前と年齢で、それぞれhogeさん、30歳であった。

    2.その直後にBさんが同じレコードを読み込んだ。 hogeさん、30歳。
      Bさんはhogeさんをfugaさんに変更し、データベースに保存した。つまり、この時点でデータベース上はfugaさん、30歳に変更された。

    3.Aさんは読み込んだデータのうち、年齢を35歳に変更し、データベースに保存しようとした。このまま保存すると、hogeさん、35歳でデータベースに保存されてしまいます。
    そうするとBさんがfugaさんに変更したことは跡形もなく無くなってしまいます。これでは困るので、Aさんが保存しようとした時に同時実行制御違反が発生します。

    「もし1,2が原因であるとすれば新しくテーブルを作って値を入力すれば直ると思っていたのですが・・

    1,2の最中であればタイミングによって同時実行制御違反が発生する可能性がありますが、新しくテーブルを作成し直し、そのテーブルのみを開いてそこで編集している限り、論理的には同時実行制御違反が発生することはあり得ません。問題が発生する環境、および手順をもう少し具体的に説明いただければ、もう少し具体的なアドバイスができるかもしれません。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2010年10月5日 15:43
    モデレータ
  • 現在0から同じように組んで問題の発生するポイントを探してみています。

    もしそれでエラーが起きるようであればまた質問を投稿しようと思います。ありがとうございました!

    2010年10月6日 4:35
  • 再度同じ作業をしていたところ,新しいテーブルの追加から2つ目のテーブルを作成し,そこに値を書き込んだ際に

    『この行は正常にデータベースにコミットされました

    ただし、コミット後にデータを再度取得中に問題が発生しました。

    そのため、この行の表示されたデータは読み取り専用です。

    この問題を解決するためには、クエリを再実行してください。』

    というメッセージが赤○にエクスクラメーションマークとと共に表示されました。

    1つ目のテーブルと同じ様にテーブルを作成したはずなのですが・・・

    何か関係があるのでしょうか?

    2010年10月6日 5:04
  • テーブルの構造がわからないのですが、保存時に何か自動的に値が設定されるような列がありませんか? その値を読み直そうとして失敗し、そのメッセージが出ているのかもしれません。
    繰り返しになりますが、問題が発生するテーブルの構造、およびその作成、値設定の手順を教えていただくと、こちらでも再現テストが可能です。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2010年10月6日 7:14
    モデレータ
  • 値設定の手順は、

    1. ソリューショネクスプローラでプロジェクト名を右クリック 追加→新しい項目→サービス べースのデータベース を選択

        Database1.mdfを作成

    2.サーバエクスプローラでデータ接続右クリック, 接続の追加 データソースをSQL Serverデータベースファイルに変更

    データベースファイル名に先ほどのDatabase1.mdfを選択 Windows認証を使用するにチェック

    3. サーバーエクスプローラでDatabase1.mdf⇒テーブルを右クリック、新しいテーブルの追加

    4. 列名とデータ型(すべてnchar(10)で10項目程度)を入力 タブ右クリックからテーブルを保存(仮にex1)

    5。Database1.mdf⇒テーブル→ex1を右クリック テーブルデータの表示 から値を入力

    6.3、4をもう一度行いテーブルex2を作成 ここに5同様値を入力すると警告が表示され、そこで右クリックSQLの実行を選択

    するとそれ以降でエラーが出る

     

    といった流れになります。自動的に値が設定される列は無いと思います。

    2010年10月6日 9:11
  • 現在は同時実行制御違反は発生していないということでよろしいでしょうか? それであれば説明がつきます。

    『この行は正常にデータベースにコミットされました

    ただし、コミット後にデータを再度取得中に問題が発生しました。

    そのため、この行の表示されたデータは読み取り専用です。

    この問題を解決するためには、クエリを再実行してください。』

    とメッセージが表示されるのは、たぶん既に全ての列で全く同じ値を持つ行が存在しているからだと思います。説明を簡単にするために、列が1つしかないテーブルで考えます。。その列名をA列とします。
    A列が3である行が既に存在している状態で、新規にA列が3である行を追加しようとすると上記のエラーが発生します。これは、新規にレコードをデータベースに保存した後、その保存したレコードを取得しようとした際に、A列が3であるレコードが2件あったためにどちらを取得してよいのか決められないのが原因です。レコードを保存した直後にそのレコードを取得するため、select * from あるテーブル where 列A='3'が用いられます。ちなみに保存した直後に取得する理由ですが、他に主キーが自動採番されるような列があった場合、その値を取得したいためです。

    さて、その後に行を変更しようとした時、 update あるテーブル set A列=変更したい値 where A列='3' を発行しようとしますが、対象レコードが2件あるためにどちらを変更して良いかわからず、以後、変更できなくなります。削除も同じ理由でできなくなります。

    と、想像していますが、いかがでしょうか?


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2010年10月6日 13:20
    モデレータ
  • 現在は新しくテーブルを組み直したため出ていません。が、列を増やした際に同様の状態になりました。列数が3以下の時は出ないようです… ちなみにtrapemiyaさんの説明での列Aの値は3でなくNULLでもおこってしまうのでしょうか? 確かに列内で同じ値がある部分はありましたが、その場合同列で同じ値を記入することができない、ということになってしまうのでしょうか…?
    2010年10月7日 12:21
  • NULLでも同じです。要するに全ての列が同じ値であるレコードがデーターベース上に複数あるため、どのレコードを更新(または削除)してよいかわからず、更新(または削除)ができない状態です。
    なぜわからなくなるかと言いますと、更新する際には、データーベース上の更新するレコードを特定するために、手で値を変更する前のレコード(データベースから読み込んだ直後のレコードとも言えます)の全ての列の値が等しいレコードをデーターベースから見つけ、それを更新しようとしますが、それが複数見つかってしまい、どれを更新するかわからなくなるからです。

    結局、全ての列が同じであるレコードが複数できてしまうと、グリッドの値を手で変える方法では更新(または削除)を行なうことができなくなります。

    以上の件は列の数には関係ないはずであり、私のところではどうしても上で書いた以上のことが起こりません・・・
    もう少し正確な再現手順を書いていただけるとお力になれるかもしれません。

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2010年10月7日 14:56
    モデレータ
  • やっと少し理解できました。。。

     

    因みに,たとえば何かの会員を管理するテーブルがあったとして,列『出身地』等を設定した場合

    嫌が応にもたとえば『埼玉県』で同じ列内に同じ値が存在することがあると思うのですが,その場合はどうなるのでしょうか?

     

    新しいテーブルを作成してからはとりあえずは起こらなくなりました。

    念のために作成した行には値を書き込むようにしています。

     

    2010年10月8日 15:21
  • テーブルは必ず行を一意に特定できるようにデザインされていなければなりません。行を一意に特定できないようにデザインすることもできてしまいますが、それは動かないプログラムを作成するのと同じことです。もし、列『出身地』という1つの列しか無いテーブルがあり、この列の値がユニークでないことを許すのであれば(同じ値が入ることを許すのであれば)、以下のようなデータが存在する時に一つの行を特定することができず、一つの行のみを変更することができません。

      会員テーブル

             『出身地』
    1レコード目  埼玉県
    2レコード目  埼玉県
    3レコード目  埼玉県

    2レコード目を東京都に変更したい。

    update 会員テーブル set 出身地 = '東京都' where ???

    2行目を特定するwhere句を書きようが無い。

    そのため、行を特定できる主キーと呼ばれる列を付加します。主キーの付け方もいろいろありますが、ここでは単に連番を保持する列『ID』を追加します。そうすると会員テーブルは以下のようになります。

      会員テーブル

             『ID』  『出身地』  
    1レコード目   1    埼玉県
    2レコード目   2    埼玉県
    3レコード目   3    埼玉県

    このようにすると2行目のみ変更したい場合、以下のようなSQLが書けます。

    update 会員テーブル set 出身地 = '東京都' where ID = 2

    さて、テーブルの設計がきちんとできることがアプリケーションの善し悪しに係わってきます。以下などが参考になりますので、目を通されることをお勧めします。上述した主キーの説明もあります。

    すぐわかるデータベースの基礎---目次
    http://itpro.nikkeibp.co.jp/article/COLUMN/20061208/256458/?ST=system

     

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    • 回答としてマーク -BALALAIKA- 2010年10月11日 6:10
    2010年10月8日 23:10
    モデレータ
  • なるほど・・・

    参考になりました。これまで教えていただいたことに留意して作成したいとおもいます。

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

    2010年10月11日 7:04