2011年01月30日

LINQ to SQL番外編 - 挿入、更新、削除の動作のカスタマイズ

   このエントリーをはてなブックマークに追加 Clip to Evernote
まず、LINQ to SQLで更新を行った時に、どのようなSQLが発行されているのか、
以下のコードで見てみましょう。


発行されるSQLは、


となります。
SQL の SETで設定されるカラムは、ContactTitleだけです。これからわかるのは、
どのカラムの値が変更されたかで、発行されるSQLが異なるということです。
つまり、動的にSQL文を組み立てているのです。

なかなかすごいことをやっているなと思うのですが、動的にSQLを組み立てること
があだになり、一度に大量のデータを更新するような場合は、SQLの組み立てに
時間がかかり、速度低下が起こる可能性もあります。これは、実際に試していない
ので、僕の想像の域を脱しませんが...

この時に、独自のSQLが使えれば、速度向上につながるかもしれません。
また、あるカラムは更新させたくないといった場合も、独自のSQLが使えれば便利です。

LINQ to SQLは、そのような要望に応えられるよう、Delete, Insert, Update を
既定のものから、別のものに置き換えることができます。
ただし、置き換え後のものは、ストアドプロシージャのみとなります。

では、さっそく、Updateのカスタマイズをやってみましょう。
まず、以下のようなストアドプロシージャを作成します。


このストアドプロシージャだと楽観的同時実行制御が行えませんが、
Updateをカスタマイズする方法を示すことが目的なので、そこは大目にみてください。

サーバーエクスプローラの[ストアドプロシージャ]のフォルダを右クリックし、
[新しいストアドプロシージャの追加]を選ぶと、エディタ部にひな形が表示されますので、
それを上記のストアドプロシージャの記述に変更します。
[保存]ボタンを押し、ストアドプロシージャを Northwindデータベースに追加します。

追加されたストアドプロシージャを Northwind.dbml の O/Rデザイナー画面の空白部にD&Dします。
すると、Northwind.dbmlにストアドプロシージャに対応するメソッドが追加されます。

O/RデザイナーのCustomers クラスをクリックし、プロパティウィンドウに、
Customersデータクラスのプロパティを表示します。
Update プロパティに、先ほど作成した UpdateCustomer メソッドを割り当てます。

以上で、Updateメソッドのカスタマイズが完了しました。

これで最初に示したコードを実行すると、


というSQLが発行されているのがわかります。

なお、


と Cityカラムを更新しようとしても、ストアドプロシージャには、この値はわたりませんので、
Cityカラムは更新されることはありません。

同様の方法で、Insert, Delete もカスタマイズすることが可能です。


LINQ to SQL番外編とは
メールマガジン『C#プログラミングレッスン』で連載した「LINQ to SQL編」には書ききれなかった情報を
「番外編」としてブログにアップしています。
併せて、メールマガジン『C#プログラミングレッスン - Linq to SQL編』も読んでいただけると、
より理解が深まると思います。
バックナンバーは、メールマガジン『C#プログラミングレッスン』書庫のページからダウンロードできます。

  

Posted by gushwell at 22:00Comments(0)TrackBack(0)

2011年01月25日

LINQ to SQL番外編 - エンティティ クラスの更新時にデータを検証するには

   このエントリーをはてなブックマークに追加 Clip to Evernote
たぶん、この記事に書いてある情報は、日本語初の情報です。
MSDNライブラリの情報も中途半端で正しい内容ではありません。

前回、変更時の値のチェックについて説明しましたが、エンティティクラス全体の更新時に
データを検証することもできます。
この更新時の検証では、業務アプリケーションの要件に応じて複数のカラムの値を見て、
検証することができます。

以下にNorthwindデータベースを例に、その手順を示します。

  1. Visual Studio のソリューションエクスプローラで、プロジェクトに追加されているNorthwind.dbml
    ファイル(LINQ to SQL クラスファイル)を右クリックします。

  2. コンテキストメニューから「[コードの表示] をクリックします。コード エディターが開き、
    NorthwindDataContext の部分クラスが表示されます。

  3. 検証メソッドを作成します。 サンプルコードのため、System.Exception例外を発生させていますが、
    本来は別の例外(あるいは独自例外)を発生させるべきかと思います。

  4. NorthwindDataContextの部分クラスに部分メソッドを追加し、検証コードを呼び出す コードを記述します。
    "partial " までタイプすると、"partial " までタイプすると、インテリセンスが働き、
    メソッド一覧が表示されますので、UpdateXxxxxx を選んでください。Xxxxxx は検証をしたいクラス名です。
    すると、以下のようなコードが挿入されます。
  5. メソッドに検証メソッドの呼び出しと、DB更新のコードを追加します。
  6. 同様に、InsertCustomerを追加します。

ExecuteDynamicInsertUpdateメソッドを呼び出すのがカギです。
なぜか、MSDNライブラリの以下のページには、このことが書いてありません。
http://msdn.microsoft.com/ja-jp/library/bb629296.aspx
これで、NorthwindDataContextクラスに検証機能を組み込むことができました。

DBを更新する側のコードを示します。

この例では、SubmitChanges メソッドを呼び出すと、InsertCustomer メソッドが呼び出され、
検証ロジックが動いた後、行が挿入されます。
★の行をコメントにして実行すると、検証で例外が発生します。
  
Posted by gushwell at 22:13Comments(4)TrackBack(0)

2011年01月23日

LINQ to SQL番外編 - 「LINQ to SQLエンティティクラス」に検証を追加する

   このエントリーをはてなブックマークに追加 Clip to Evernote

今回は、「LINQ to SQLエンティティクラス」にデータの検証ロジックを追加する方法を 説明します。
検証ロジックを追加することで、特定の列が変更されたときに検証を行う ことが可能になります。
O/Rデザイナーが生成する「LINQ to SQLエンティティクラス」には、いくつかの パーシャルメソッドが用意されており、
このパーシャルメソッドを実装することで、 データの挿入、変更時における検証処理を実現できます。


■検証コードの作成手順

ここでは、(LINQ to SQLエンティティクラスの)CategoryクラスのCategoryNameカラムが
変更された時に、ある検証を行うための手順を示します。


  1. O/Rデザイナーで、.dbmlを開きます。

  2. デザイナーに表示されるCategoryクラスを右クリックし、[コードの表示]をク リックします。

  3. 選択したクラスのパーシャルクラスが表示されますので、このクラス内で、 以下のように、"partial " までタイプすると、
    インテリセンスが働き、メソッド一覧が表示されますので、実装したいメ ソッド(OnCategoryNameChanging)を選択してください。
     
  4. OnCategoryNameChangingを選択すると、以下のようなコードが挿入されます。
     
  5. メソッドに検証ロジックを追加できます。ここでは、すべてが数字ならエラーにしています。
     
これで、検証ロジックを追加することができました。



■検証ロジックの動作確認

以下のようなコードを書いて、動作を確認してみます。

 

★の行で、OnCategoryNameChanging()が呼び出され、例外が発生しているのを確認できると思います。
  
Posted by gushwell at 22:25Comments(0)TrackBack(0)

2011年01月18日

LINQ to SQL番外編 - ADO.NETとの相互運用

   このエントリーをはてなブックマークに追加 Clip to Evernote
ADO.NETの接続型アクセスを使った以下のようなコードがあったとします。

ここにLINQのコードを追加することができます。
DataContextを作成する際に、既存の接続を指定するだけです。
Connectionプロパティを使用して、接続を明示的に閉じることもできます。
  
Posted by gushwell at 22:04Comments(0)TrackBack(0)

2011年01月16日

LINQ to SQL番外編 - 独自メソッドを追加する

   このエントリーをはてなブックマークに追加 Clip to Evernote
ADO.NET2.0のTableAdapterでは、GetXxxxxById() などといった独自のメソッドを
追加し、ビジネスロジック層からは、SQL文を意識しないで目的のデータを取得で
きるようにする方法がありました。

LINQ to SQLで同様のことを行う場合は、DataContextにメソッドを追加すること
で、対応できます。
コードジェネレータは用意されていないので、手動で追加することになります。


今回は、「ProductIDを指定しProductオブジェクトを取得する」メソッドを追加してみましょう。

1. Northwind.dbmlのO/Rデザイナーを開きます。

2. デザイナーの空白部分を右クリックし、[コードの表示]を選択します。

3. パーシャルクラス NorthwindDataContext が表示されますので、ここでGetProductById()メソッドを追加します。


もちろん、このメソッド内で、ストアドプロシージャを呼び出すことも可能です。
  
Posted by gushwell at 23:00Comments(0)TrackBack(0)

2011年01月12日

LINQ to SQL番外編 - ColumnAttribute.UpdateCheck プロパティ

   このエントリーをはてなブックマークに追加 Clip to Evernote
前回の記事でUpdateCheckプロパティについて触れましたが、もう少し詳しくこの
UpdateCheckについてみていきましょう。

このプロパティは、LINQ to SQL がオプティミスティック同時実行競合を検出する方法を
取得または設定するものです。以下の3つの列挙値を利用できます。

  1. Always  競合の検出に常にこの列を使用します。

  2. Never  競合の検出にこの列を使用しません。

  3. WhenChanged  メンバーがアプリケーションによって変更された場合のみ、この列を使用します。

既定値は、Alwaysです。

このプロパティ値を変更することで、オプティミスティック同時実行競合を検出
する方法を変更することができます。

このプロパティ値を変更する手順を示します。

  1. ソリューションエクスプローラで、Northwind.dbmlをダブルクリックし、O/Rデザイナー画面を開きます。

  2. エンティティクラスのプロパティ(以降メンバーと呼びます)をマウスでクリックします。

  3. プロパティウィンドウに、このメンバーに対応したプロパティが表示されます。

  4. [更新チェック]プロパティの値をAlways, Never, WhenChanged から選択します。

この操作をやることで、Northwind.designer.csの 該当プロパティ(メンバー)
のColumn属性のUpdateCheckプロパティの値が変更されます。

なお、このプロパティが有効なのは、どのメンバーも、IsVersion=true として指定されていない場合だけです。

いずれかのメンバーに、IsVersion=true が指定されている場合、UpdateCheckは無効となります。
  
Posted by gushwell at 23:30Comments(0)TrackBack(0)

2011年01月10日

LINQ to SQL番外編 - timestamp列とUpdateCheckプロパティ

   このエントリーをはてなブックマークに追加 Clip to Evernote
中断していた「LINQ to SQL番外編」を再開します。

LINQ to SQLでは、楽観的同時実行制御の仕組みが組み込まれています。
たとえば、Customers テーブルの行を更新する場合、LINQ to SQLは
以下のような UPDATE文を発行します。

パラメータ p0, p1, p2... には、変更前の値が渡されます。
このSQLは、他のユーザによって変更されていない場合にだけ、このUPDATE文
が成功することになりますので、他のユーザによる変更有無を把握できるわけです。

LINQ to SQLでは各カラムに規定値として、
UpdateCheck = UpdateCheck.Always
が設定されています。これにより上記SQLのWHERE句で変更チェックが行われることになります。

しかし、すべてのカラムで変更有無のチェックすることは、パフォーマンスに影響することもあります。
なのでもっと単純な方法でこの制御を行いたい場合もあります。

そのような場合で一般的なのは、Timestamp型のカラムをテーブルに追加することです。
Timestamp型がテーブルにあると、O/Rデザイナーはカラム属性のIsVersionプロパティに
Trueが設定されます。これにより、競合の発生の判断に
Timestamp型のカラムのみが利用されることになります。

O/Rデザイナーが付加する属性を以下に示します。(TimeStampという名前のカラムにしています)

また、

この場合のUPDATE文は、

となり、主キーとTimeStampカラムだけが、チェックされる単純なSQL文となります。

最近では、GUIDをカラムに追加して、同様のことを行うこともあるようですが、
LINQ to SQLがサポートしているかどうかまでは、調べきっていません。
ご存知の方がいましたら、コメントいただけると嬉しいです。

  
Posted by gushwell at 21:27Comments(0)TrackBack(0)

2011年01月08日

『C#プログラミングレッスン』 LINQ to SQL編

   このエントリーをはてなブックマークに追加 Clip to Evernote
メールマガジン『C#プログラミングレッスン』のバックナンバー「LINQ to SQL編」を

メールマガジン『C#プログラミングレッスン』書庫

からダウンロードできるようにしました。
  
Posted by gushwell at 16:39Comments(0)TrackBack(1)