2011年02月13日

2011年02月10日

LINQ to SQL番外編 - 競合時の処理

   このエントリーをはてなブックマークに追加 Clip to Evernote
LINQ to SQLでは、ChangeConflictException の例外が発生した場合、その競合解決に、
DataContext.ChangeConflictsコレクションのResolveAllメソッドが利用できます。

そのコード例を示します。


ResolveAllメソッドの引数の型であるRefreshModeには、
 KeepChanges、KeepCurrentValues、OverwriteCurrentValues
の3つの値があり、この値によりどのように競合を解決するのかを指定します。

KeepChanges
変更された値と変更前(他のユーザによって変更された)値をマージします。
両方で変更されていた場合は、当該クライアントの変更を優先します。

KeepCurrentValues
他のユーザによって変更された値は無視され、当該クライアントからの変更が有効になります。

OverwriteCurrentValues
当該クライアントによって変更された値は無視され、他ユーザによって変更された値が有効になります。

これを表で表すと以下のようになります。
  カラムA カラムB カラムC
1.User1,USer2が読み込んだ値 aaa bbb ccc
2.User1が更新 sss ttt  
3.User2が更新 xxx   yyy
結果:KeepChanges xxx ttt yyy
結果:KeepCurrentValues xxx bbb yyy
結果:OverwriteCurrentValues sss ttt ccc

※ユーザ2で競合が発生し、ChangeConflicts.ResolveAllで競合解決を図った場合の例

競合の詳細な情報を取得したい場合は、DataContext.ChangeConflictsプロパティを参照します。
以下にそのサンプルコードを示します。



『LINQ to SQL番外編』は、今回を持って終了です。   
Posted by gushwell at 22:26Comments(0)TrackBack(0)

2011年02月06日

LINQ to SQL番外編 - 同時実行例外をいつスローさせるのか

   このエントリーをはてなブックマークに追加 Clip to Evernote
LINQ to SQLでは、楽観的同時実行制御の仕組みが組み込まれています。

たとえば、Customersテーブルの行のContactNameカラムをSubmitChangesメソッドで更新する場合、
LINQ to SQLは以下のような UPDATE文を発行します。


パラメータ p0, p1, p2... には、変更前の値が渡されます。
LINQ to SQL では、これによって他のユーザによって変更されていない場合にだけ、
このUPDATE文が成功することになります。
失敗した場合は、System.Data.Linq.ChangeConflictException例外が発生しますので、
他のユーザによる変更を把握できることになります。

SubmitChangesメソッドには引数を持つメソッドがオーバーロードされていて、
この例外が発生するタイミングを以下の2種類から指定できます。

1. 最初の失敗のときにのみ、例外をスローする

2. 失敗したすべての更新についての情報を収集してから、例外をスローする。

具体的な例外発生時の処理を指定したコードを示します。

競合発生した場合、どのような対応ができるのかは、次回説明します。


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

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

2011年02月03日

LINQ to SQL番外編 - SelectWithUpdlock メソッドを自作

   このエントリーをはてなブックマークに追加 Clip to Evernote
LINQ to SQLでは、UPDLOCK付きの SQL文を発行させることができません。
以下のように書ければ良いのですが...
このような場合は、しかたないので、ExecuteQueryを使います。
これで、UPDLOCK付きのSELECT文を発行できます。

ただ、こういったSQLは、ストアドプロシージャを使う方が良いかな、と個人的には思います。
このあたり、LINQ to SQLの経験豊富な方の意見を聞いてみたいものです。

しかし、いちいちSQL文を手書きするのはイヤですよね。
ちょっと工夫してみましょう。

こんなメソッドを作ってみました。
このメソッドを使うコードは、こんな感じです。
※ 拡張メソッドにすれば、もっと使いやすくなりますね。

SelectWithUpdlockが、何をやっているかというと、
で、queryの実際のSQL文を文字列として取り出しています。
次に、
で、SQL文の FORM句の後ろに、"WITH (UPDLOCK)" という文字列を追加した、SQL文を作ります。
3行目の
ですが、Parametersに入っているパラメータの値を、配列に変換しています。
まず、Castメソッドを使って、Parametersを IEnumerable
変換し、クエリ演算子が利用できるようにします。そして、Select(p => p.Value)で、
パラメータのシーケンスを取り出し、ToArray()で配列にします。

最後に

で、クエリを発行し、結果を戻しています。

このSelectWithUpdlockメソッドですが、すべてのクエリ式で試したわけではない
ですが、それなりに動いているみたいです。
かなり、強引な方法ですが、これを応用すれば、LINQ to SQLが対応していないSQL文の実行も、
わざわざSQL文を書かなくても、LINQ to SQL上で実行することが可能になる?かもしれません。

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

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)