2010年07月19日

DataSetデザイナーで「列には有効なDataTypeが必要です」のエラー

   このエントリーをはてなブックマークに追加 Clip to Evernote
型付DataSet の プロパティの型を、独自に定義したenum型に変更していたのだけれど、
プログラムを修正していたら、いつのまにか、DataTypeが
「列には有効なDataTypeが必要です。」
というエラーメッセージが出て、DataSetデザイナーが開かなくなってしまいました。

初めは、どこが悪いのかまったくわからず Visual Studio 2008を起動しなおしたり、
DataSet.xsd をソース管理から再取得したりしましたが、エラーは出続けたままです。

いろいろ調べて、xxxxDataSet.xsd ファイル(これは、xmlファイルです)の


の部分が正しくないことに気がつきました。
リファクタリングで、このAbcEnum 型が定義されているプロジェクトを、別のプロジェクトに移したのが原因でした。

DataSetデザイナーが、AbcEnumの型を読み込もうとしても、指定したアセンブリには、その AbcENum型は存在しないので、

「列には有効なDataTypeが必要です。」

というエラーになっているようでした。
xxxxDataSet.xsd の中身を手で書き直すことで、無事DataSetデザイナーを開くことが出来ました。
  

Posted by gushwell at 23:20Comments(0)TrackBack(0)

2007年06月06日

TableAdapterのベースクラス

   このエントリーをはてなブックマークに追加 Clip to Evernote
ずいぶん前だが、
C#のパーシャルクラスとデザイナが生成したコードについて考えてみる

という記事の中で、 「なちゃさん」から
---
TableAdapterは、デザイナでBaseClassプロパティで基底クラスを指定できる
--
ということを教えていただきました。

いままで確かめてみる機会がありませんでしたが、やっと利用する機会が出てきました。

これを使えば、いくつもある TableAdapter で同じコードを書く必要がなくなります。

以下、書いてみたコードの断片。


 public abstract class AbstractTableAdatpter : Component {
private const string FieldNameCommandCollection = "_commandCollection";

private SqlCommand[] CommandCollection {
get {
Type type = this.GetType();
FieldInfo field = type.GetField(FieldNameCommandCollection,
BindingFlags.NonPublic | BindingFlags.Instance);
SqlCommand[] array = (SqlCommand[])field.GetValue(this);
return array;
}
}

// 上記 CommandCollectionを使って、実装
// タイムアウト値の取得と設定を行う。
public int CommandTimeout {
get { ... }
set { ... ]
}
...
}

_adapter フィールドや、_connection フィールドも同じようにしてやれば、
いろんなことが共通化出来そうです。

ただ、まだ動かしていないので、正しく動くかどうかわかりません...
  
Posted by gushwell at 20:51Comments(0)TrackBack(0)

2007年05月31日

DataSetのカラムで列挙型を扱うには

   このエントリーをはてなブックマークに追加 Clip to Evernote
型付DataSetのテーブルのカラムの型を、int ではなく、独自の列挙型にするには、2つの方法がある。

ひとつは、型付DataSetの定義を行う場合に列のデータ型を列挙型に指定する方法。
これは、デザイナー画面で、DataTypeプロパティの値を System.Int32 などから、独自の型 Gushwell.Genderなどを指定してあげればよい。
ドロップダウンリストには現れないので、手入力になる。

もうひとつは、partial クラスを使う方法。

型付DataRowクラスの partialクラスを作成し、その中に、列挙子用のプロパティを定義し、データ変換コードを書けばよい。

例えば、Gender というカラムがあった場合、

public partial class MyRow : System.Data.DataRow {
public Gender EnumGender {
get {
try {
return (Gender)(this.Gender);
} catch {
return Gender.Unknown;
}
}
set {
this.Gender = (int)value;
}
}
}

のように書けば良い。C#からは、Genderカラムではなく、EnumGenderカラムを参照するようにする。こうすることで、間接的ではあるが、DBのカラムを列挙型として扱うことができる。

後者のやり方は、try-catchで例外処理を記述できるのがメリット。
  
Posted by gushwell at 21:38Comments(0)TrackBack(0)

2007年05月10日

制約を有効にできませんでした。行に入力できるのは、Null 以外の値...

   このエントリーをはてなブックマークに追加 Clip to Evernote
C#で、型付DataSetを使ったプログラムをデバッグしていたら、

「制約を有効にできませんでした。行に入力できるのは、Null 以外の値、一意な値、あるいは外部キーですが、この制約の違反が 1 つ以上の行で発生しています。」

というエラーが出るようになった。
なんで??

何のことはない、DataTableの カラムのプロパティが間違っていたのだが、この間違いに気が付くのに結構時間がかかってしまった。

具体的には、MaxLengthの長さが実際よりも短かった。。。
途中で、スキーマを変更したときに、こっちを変更するのを忘れていたみたい。

一生懸命 Null制約と外部キー制約あたりを調べていて、どこもおかしなところは無いのに、と見当ちがいの場所を調べていた orz
  
Posted by gushwell at 21:42Comments(0)TrackBack(0)

2006年07月13日

TableAdapter で Command のタイムアウトを設定するには

   このエントリーをはてなブックマークに追加 Clip to Evernote
 public partial class MyTableAdapter {
public int CommandTimeout {
get {
return ( this.CommandCollection[0].CommandTimeout );
}

set {
for ( int i = 0; i < this.CommandCollection.Length; i++ ) {
if ( ( this.CommandCollection[i] != null ) ) {
( (System.Data.SqlClient.SqlCommand)
( this.CommandCollection[i] ) ).CommandTimeout = value;
}
}
}
}
}

C#2.0の新機能である partial クラスを使い、CommandTimeout プロパティを新設すれば、外から Timeout を設定できる。
でも、TableAdapterの数だけ、コーディングしなければいけないのは、気に入らない。
良い方法がないかな。

ちなみに、ネットのあるページでは、CommandCollection ではなく、_commandCollection を使っているものがあったが、これだと、null参照する場合があるので、ダメ。

  
Posted by gushwell at 23:01Comments(0)TrackBack(0)

2006年07月05日

分散トランザクションで発生するエラー

   このエントリーをはてなブックマークに追加 Clip to Evernote
分散トランザクションで発生するエラーについて調べていたら、マイクロソフトサポートオンラインの以下のページにたどり着いた。

有効なトランザクション記述子が付属する必要があるので、「新しい要求が開始されるのが許可されません」

なんと、.NET Framework2.0 のパッチが出ていたんですね。

ちなみに、僕のPCで出たエラーの一つは、
「新しい要求は、有効なトランザクション記述子を含んでいる必要があるので、この要求を開始できません」

たぶん、サポートオンラインのメッセージと同じだと思うのだが、このページが自動翻訳なので、微妙に言い回しが異なる。  
Posted by gushwell at 23:29Comments(0)TrackBack(0)

2006年07月03日

ADO.NET2.0のDataSet の Modifier プロパティ

   このエントリーをはてなブックマークに追加 Clip to Evernote
ADO.NET2.0 の DataSet には、Modifier プロパティというものがあり、ここを public にすると Connection プロパティが、internal から public に変更できる。
こうすれば、TableAdapter の Connection を自分で設定することが可能だ。

SqlConnection conn = new SqlConnection(...);
MyTableAdapter.Connection = conn;

なぜ、こんなことが必要なのか。
それは、TransaciotnScope でトランザクション処理をするときに必要になる。
分散トランザクションに昇格しても良いのならば、わざわざ Connectionを自分でnew する必要もないのだが、単一のデータベースに対しては、やはり、分散トランザクションを避けたい。
これを避けるには、TransaciotnScope 内のコネクションを一つに限定すればOKだ。
この際に、上記 Modifier プロパティを public にすると良い。
そうすれば、以下のようなコードが書ける。

using ( TransactionScope tx = new TransactionScope() )
using ( SqlConnection conn = new SqlConnection(...) ) {
myTableAdapter1.Connection = conn;
myTableAdapter2.Connection = conn;
... // ここで、TableAdapter を使ったUpdate処理
tx.Complete();
}

ただ、Toyプログラムならばこれで十分なのだけれど、トランザクション処理と、テーブル操作の処理をきれいに分割しようとすると、ちょっと困ってしまう。

using (TransactionScope tx = new TransactionScope()) {
SqlConnection conn = new SqlConnection(...);
MyWork1(); // この中で、TableAdapter を使ったUpdate処理
MyWork2(); // この中で、TableAdapter を使ったUpdate処理
tx.Complete();
}

MyWork1(conn) のように、SqlConnection インスタンスを引数で渡し、MyWork1() のなかで、コネクションをTableAdapterにセットするという手もあるが、どうも、コネクションを引数で受け渡すのは、好みじゃない。

partial クラスを利用し、Modifier プロパティをinternalのまま対応する方法もあるが、結局、Connectionオブジェクトを引き渡すのは同じこと。

マルチスレッド環境を考えなければ、シングルトンを使って、Connectionオブジェクトを操作することもできるけれど、後からマルチスレッドに対応しようとすると苦労することになる。

みんなは、どうしているんだろう。
  
Posted by gushwell at 22:09Comments(2)TrackBack(1)

2006年04月25日

TransactionScopeでの分散トランザクションへの昇格

   このエントリーをはてなブックマークに追加 Clip to Evernote
.NET Framework2.0 の ADO.NETでは、TransactionScope を使った場合、
自動的に、分散トランザクションに昇格するようだ。
ただ、単一のデータベースであるにも関わらず、

----
分散トランザクション マネージャ (MSDTC) のネットワーク アクセスは
無効になっています。 コンポーネント サービス管理ツールを使用して、
MSDTC のセキュリティ構成でネットワーク アクセスの DTC を有効にして
ください。
----

という例外が発生してしまう。
DBはそれほど詳しくないので、何か大きな見落としが
あるのかな。それとも大きな勘違いをしているのか。。。
  
Posted by gushwell at 22:56Comments(2)TrackBack(0)