Ktouth Brand. on Web

け〜くんこと K.Ktouth のだらだらした日常と突発的に作るプログラムや読み物とかの雑多サイト



[2008年01月04日]

Linq to SQLで悩む

2008年01月05日 08:34更新 筆者:K.Ktouth

Visual Studio 2008 Professional Edition アップグレード(AA)

ただいま内部のデータをLinq to SQLでデザインしてるんですが、アソシエーション周りのコードでお悩み中。
Linq to SQLはクラスデザイナと連携していていろいろとコードを自動生成してくれて便利なんですが、当初からちょっと困った事が連発してます(笑)

どう実装しようか、丸一日悩んじゃったよあせ

1: SQL Server Compact Edition サポートが制限されている

VS2008には、Access形式に変わるファイル単体型データベースシステムとして SQLServer Ce が付属してくるんですが、コレに対し Linq to SQL がきちんと対応してくれていない orz

  • Visual Studio 2008 Express Editions FAQ

    SQL Server Compact Edition は、Windows データベース開発に最適な、軽量で簡単に展開できるデータベース システムです。
    メモリの占有領域は 2 MB で、管理する必要がないので、ほとんどのデータ ストレージの作成に最適なソリューションです。
    SQL Server Compact Edition には次のような制限事項があります。

    • リモート接続を使用できません。
    • LINQ to SQL 対応のデザイン時ツールとの互換性がありません。
    • ストアド プロシージャはサポートされません。

    (FAQ 45.より抜粋)

調べたら、明確に制限事項として書かれていました。
要はフルサポートで使いたければExpress Editionを選択しろと言う事のようです。
まぁ、今回のようなデータ構造がシンプルな場合は、サポート無しでも十分デザインできるので良いんですが。

2: 自動生成コードに検証コードを挟む余地がない

で、一日悩んだ原因。

  • クラスFoo、BarはともにテーブルFoo、Barに対応している。
  • クラスFooは private 属性の BarID プロパティを持つ。
  • クラスFooとBarは一対多のアソシエーションを持つ。
  • Foo.Bar プロパティに指定できる Bar インスタンスは、テーブルBarに登録されているもののみとする。

以上の条件でデザインしていたのですが、自動生成されるコードが以下の通り。

[Association(...)]
public Bar Bar
{
 set
 {
  if ((this._Bar.Entity != value))
  {
   this.SendPropertyChanging();
   this._Bar.Entity = value;
   this.SendPropertyChanged("Bar");
  }
 }
}

get アクセサと Association 属性の引数は省略。
困った事に、中央3行の値を差し替えるコードにおいて、与えられた value が正しいものかを検証するコードを差し挟む余地がないのですな。
通常なら関連ですので、データベースに登録する際に検証するコードが実行されるようになっていますが、「プロパティを変更する」検証可能な事は検証しておきたいと思うんです。
EntityRef<T> 構造体のコードを追跡しましたがこちらにもコードを挟む余地はないようです。
ちなみにアソシエーションじゃないテーブルの絡むデータのプロパティの実装は、前後3行の前に partial 指定のヘルパーメソッドを呼び出すコードがあるため、そう言った機能は簡単に実装可能です。

で試してみた事……

  1. BarIDプロパティの変更前partialメソッドに検証コードを追加してみた

    EntityRef<T>.Entity { set; } メソッドに外部のフィールドを変更する機能があるわけもなく、BarIDはデータベース更新まで変更が反映されない模様。
    従って、検証コードをそこに書いても呼び出されません orz

  2. Bar アソシエーションプロパティを隠蔽、ラッパープロパティを追加

    なんか、無理矢理書いたせいか無限ループ化したっぽいので慌てて元に戻しました(笑)

  3. いっそアソシエーションプロパティを自前で実装する

    コレが一番シンプルで面倒のないコードになりそうなんですが、そうするとデザイナに関連の表示が無くなるわけで。
    むしろそれなら最初からデザイナ無しでコード記述しても一緒という結果に。

とまぁ、なかなかに困ったちゃんモードです。
この日記を書き終わった後、最後に思いついた方法「PropertyChangedイベントに検証と値のロールバックコードを追加する」を試してみたいと思います。
要は値が変わったというイベントで、検証して無効な値だったらBarIDを参照して正しい値を再度登録する……という結構面倒な事をしなきゃならないわけですが、まぁ、ほかに自動生成コードとケンカしない方法はなさそうです。

本日のリンク元
アンテナ
その他のリンク元
検索