DOBON.NET DOBON.NETプログラミング掲示板過去ログ

エラー「制約を有効にできませんでした.....」について

環境/言語:[Windows Vista/7 C# VC2010 Winアプリ]
分類:[.NET]

お世話になります。

下記のエラーが出て解決策がわからないので教えてください。
「制約を有効にできませんでした。行に入力できるのは、Null 以外の値、一意な値、あるいは外部キーですが、この制約の違反が 1 つ以上の行で発生しています。」

エラーの出るコード(下記の、FillBy....でおきます)
DateTime ThisYear = new DateTime(DateTime.Now.Year, 1, 1);
DateTime EndThisYear = new DateTime(DateTime.Now.Year, 12, 31);

byoriDataDataSet1.EnforceConstraints = false;
this.bmlTableTableAdapter.FillByOrderDateStartToEnd(this.byoriDataDataSet1.BmlTable, ThisYear.ToShortDateString(), EndThisYear.ToShortDateString());
byoriDataDataSet1.EnforceConstraints = true;

上記コードは、Form_load()内のため起動時に表示されます。
実際、dataGridView には、赤マークがありポイントすると
「Column 'Bui'が MaxLength の制限を超えています」と表示されます。

で、ググってみたとこ
http://bbs.wankuma.com/index.cgi?mode=al2&namber=46580&KLOG=79
に同じような記述があり、その中の真ん中辺の「 魔界の仮面弁士 」サンの
内容を元にさらに調べました。

「イミディエイトウインドウ」で
? this.byoriDataDataSet1.BmlTable.GetErrors().Length
2
? this.byoriDataDataSet1.BmlTable.GetErrors()[2].RowError
配列インデックスの境界外です

と出ました。

さらにこの中で別のところで言っている、テーブルの変更など行ったか?
について、このテーブルも同様に変更してます。
この'Bui'については、varchar(10)からvarchar(50)に変更しました。
実際のデータは、数字文字を34文字書いてます。
2011/10/04(Tue) 16:24:13 編集(投稿者)

■No29138に返信(Hiroさんの記事)
> 「イミディエイトウインドウ」で
> ? this.byoriDataDataSet1.BmlTable.GetErrors().Length
> 2
> ? this.byoriDataDataSet1.BmlTable.GetErrors()[2].RowError
> 配列インデックスの境界外です

それは別のエラーです。
Length が 2 なら、指定できる配列インデックスは [0] または [1] ですよ。



> この'Bui'については、varchar(10)からvarchar(50)に変更しました。
nvarchar(50) ではなく、varchar(50) なのですね?

> 実際のデータは、数字文字を34文字書いてます。
最大長を超えているとの事ですので、全角数字が含まれていたり、
データの末尾に空白文字が含まれていたりしないかを確認してみてください。

以前あった話ですが、一見すると「123」という文字列だと思われていた物が、
実は改行が混入した「123(改行)456789……」という複数行データになっており、
実際にはフィールド長を超えていて登録エラーになっていたという話もあります。
■No29139に返信(魔界の仮面弁士さんの記事)
> 2011/10/04(Tue) 16:24:13 編集(投稿者)
>
> ■No29138に返信(Hiroさんの記事)
>>「イミディエイトウインドウ」で
>>? this.byoriDataDataSet1.BmlTable.GetErrors().Length
>>2
>>? this.byoriDataDataSet1.BmlTable.GetErrors()[2].RowError
>>配列インデックスの境界外です
>
> それは別のエラーです。
> Length が 2 なら、指定できる配列インデックスは [0] または [1] ですよ。
>
素早いレスありがとうございます。
確認したところ、
? this.byoriDataDataSet1.BmlTable.GetErrors()[1].RowError
"Column 'Bui' が MaxLength の制限を超えています。"
? this.byoriDataDataSet1.BmlTable.GetErrors()[0].RowError
"Column 'Bui' が MaxLength の制限を超えています。"

とでました。文字数が多いという意味のようですので調べます。
■No29140に返信(Hiroさんの記事)
> ■No29139に返信(魔界の仮面弁士さんの記事)
> とでました。文字数が多いという意味のようですので調べます。

書き込みで文字数を見ていましたが、正しく34文字のみの書き込みのようです。
その後、再表示をかけると上記のエラーになります。

テーブルの項目の文字数を変更したときに、しなければいけないところや確認の必要な個所はありますでしょうか?
やったとこは、サーバエクスプローラー内でテーブルの更新、xxxxxxx.xsdの該当テーブルのFill,GetData()の更新、Update...も更新しました。

実際のその部分の定義
Bui varchar(50) Checked
■No29141に返信(Hiroさんの記事)
> テーブルの項目の文字数を変更したときに、しなければいけないところや確認の必要な個所はありますでしょうか?

varchar(50) というのは「データベース」側の話だと思いますが、
現在問題になっているのはデータベース側ではなく、DataSet 側のはずです。

恐らくは型付データセットを利用しているのかと思いますので、
DataTable 上の該当列の定義を再確認してみてください。


> 正しく34文字のみの書き込みのようです。
今回は直接関係ありませんが、「34文字」では正しい検査となりません。

nvarchar なら文字数判定で良いですが、
varchar の場合はデータ長で判定する必要があるからです。一応念のため。

# 「34文字」ではなく「半角数字のみ34文字」なら問題無し。
■No29142に返信(魔界の仮面弁士さんの記事)
> 現在問題になっているのはデータベース側ではなく、DataSet 側のはずです。
> 恐らくは型付データセットを利用しているのかと思いますので、
> DataTable 上の該当列の定義を再確認してみてください。
「DataSet 側」とは、dataGridViewのヘッダーの定義?ですか?
TableAdapter.FillBy...で取得時点でエラーになっているので、DataSet 側をセットしている部分が分かりません。

>
> nvarchar なら文字数判定で良いですが、
> varchar の場合はデータ長で判定する必要があるからです。一応念のため。
>
> # 「34文字」ではなく「半角数字のみ34文字」なら問題無し。
今回は、半角数字のみです。

ご説明いただいた部分(前半)の意味が良分からず申し訳ありません。
調べてみてわかったことですが、xxxxxxDataSet1 がありこの中に各テーブルがあります。
その中で、今回項目の文字数を変更したテーブル(複数)を見たら、対象のColumnBuiとBuiColumn内のMaxLengthは、更新前の値、10のままでした。

サーバーエクスプローラのテーブルで変更した内容がうまく反映されていないようです。

これは、xxxxxx.xsd 内での変更がうまくいっていないのでしょうか?作成した時に作られる Fill, GetData() については更新しました。それだけではダメなんでしょうか?
■No29144に返信(Hiroさんの記事)
> TableAdapter.FillBy...で取得時点でエラーになっているので、DataSet 側をセットしている部分が分かりません。

FillBy系メソッドは、引数に指定した DataSet/DataTable に対して
データを埋め込む(Fillする)処理です。

通常はここに、型付データセット(*.xsd ファイル等で定義される)の
変数を渡します。今回は this.byoriDataDataSet1.BmlTable ですよね。

このテーブルには、列名、データ型、Null許可、データ長、主キー等の
情報が含まれているはずです。(DB側ではなく)C# 側の定義の確認をお願いします。


■No29150に返信(Hiroさんの記事)
> 調べてみてわかったことですが、xxxxxxDataSet1 がありこの中に各テーブルがあります。
そのテーブルは、TableAdapter 生成時に自動生成させることもできますし、
手動でテーブル定義を作ることもできます。


> その中で、今回項目の文字数を変更したテーブル(複数)を見たら、対象のColumnBuiとBuiColumn内のMaxLengthは、更新前の値、10のままでした。
あら、予想通り…。

データベース側を更新した場合は、型付DataSetの定義も更新する必要があります。

テーブル定義が自動更新されるのは、既定のクエリ(GetData/Fill)を
再設定した場合です(テーブル定義を再更新するか確認メッセージが出ます)。
追加クエリ(GetDataBy何某/FillBy何某など)を更新した場合には変化しません。

また、クエリが複雑な場合やDB固有の文法が使われていた場合、
あるいは自分で列定義を調整していた場合などは、列定義の自動認識に
失敗する事がありますので、クエリ調整の際には、
 ・列定義の確認
 ・インデックス情報の確認
 ・クエリパラメータのデータ型確認
 ・自動作成される更新クエリ/削除クエリの調整
も行った方が良いでしょう。特にクエリパラメータについては、
char と varchar 、datetime と date などが誤認識されるケースが
あるため、手動で調整を行う事が望ましいです。
■No29151に返信(魔界の仮面弁士さんの記事)
> あるいは自分で列定義を調整していた場合などは、列定義の自動認識に
> 失敗する事がありますので、クエリ調整の際には、
>  :
> あるため、手動で調整を行う事が望ましいです。

大変お世話になりました。結果を申し上げますと、型付データセット(*.xsd ファイル等で定義される内容が、DBを更新した時、Fill,GetData()を再設定すると今までは、更新されていたのですが、今回、何らかの理由で更新されていなかったようです。

そこで、*.xsd内のテーブルの項目のDataColumnを(今回は、Bui)のプロパティを直接書き換えてやることで修復できました。

今回の件で、DB側とアプリ側(DataSet)それぞれ「一致させているんだ」ということを知りました。また、xsdがアプリ側の設定をしていることも。

ありがとうございました。
解決のチェック忘れてました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板