- PR -

【LINQ to SQL】 更新ロジックのカスタマイズ

投稿者投稿内容
つと
会議室デビュー日: 2003/01/10
投稿数: 10
投稿日時: 2008-05-22 17:27
LINQ to SQLの挿入・更新・削除の動作をストアドプロシージャを使うようにカスタマイズしています。
その際、オプティミスティック同時実行の競合に対応(SubmitChangeでChangeConflictExceptionをスロー)したいのですが良い方法が思いつきません。

更新ロジックを「ライタイムを使用」とした場合の同時実行の競合は(推測でしかありませんが)「更新されたレコード数が 0件 かどうか」で検出していると認識しています。
更新ロジックをカスタマイズした場合も、それと同じロジックにしたいと考えているのですが、ランタイムがどのようにして更新件数を取得しているのかわかりません。

また、競合の判定方法を解決したとしても、カスタマイズ時のデザイナが作成したコード(ストアドを呼んでいる部分)はデザイン更新時に上書きされてしまうので手を入れるわけにもいかず、どこで例外をスローすればいいのか悩んでいます。

同じ問題を解決した方、情報をお持ちの方は是非アドバイスお願い致します。

環境は VisualStudio2008Pro(C#)& SQLServer2005Express です。


[ メッセージ編集済み 編集者: つと 編集日時 2008-05-22 17:31 ]
どっとねっとふぁん
ぬし
会議室デビュー日: 2005/02/23
投稿数: 935
投稿日時: 2008-05-22 17:35
LINQ to SQLクラスで生成されているPartialMethodの実装を適切に行うことでできるんじゃないかと思います。

つと
会議室デビュー日: 2003/01/10
投稿数: 10
投稿日時: 2008-05-22 17:59
ご返信ありがとうございます。
しかしながら使えそうなメソッドがなさそうなのです。

ランタイムのロジックを選択した場合は UpdateXXXX 等の partialメソッド があるのですが、カスタマイズを選択するとこのメソッドが実装されるようになっており、やはり手をつけられません…
Access
ぬし
会議室デビュー日: 2002/04/08
投稿数: 829
投稿日時: 2008-05-23 06:51
DataContextクラスに手動でメソッドを作成するか
ストアドプロシージャをデザイナのメソッドペインにドラッグして作成したらどうでしょうか。

こんな感じです。

コード:
CREATE PROCEDURE [dbo.UpdateAuthor]

  @ID UniqueIdentifiler output,
  @LastName varchar(50),
  @FirstName varchar(50),
  @TimeStamp timestamp

AS 

DECLARE @RecordsUpdated int

UPDATE Author
SET LastName = @LastName,
    FirstName = @FirstName
WHERE ID = @ID AND
    [TimeStamp] = @TimeStamp

SELECT @RecordsUpdated = @@RowCount

IF @RecordsUpdated = 1 BEGIN

  -- Add auditing record

END 

RETURN @RecordsUpdated

-----------------------------------------

[Function(Name:"dbo.UpdateAuthor")]
public int AuthorUpdate(
 [Parameter(Name="ID")] Guid ID,
 [Parameter(Name="LastName")] string lastName,
 [Parameter(Name="FirstName")] string firstName,
 [Parameter(Name="TimeStamp")] byte[] timeStamp)
{
 ...

 IExecuteResult result = this.ExecuteMethodCall(
   this, ((MethodInfo)(MethodInfo.GetCurrentMethod())),
   ID, lastName, firstName, timeStamp);
 ID = (Guid)(result.GetParameterValue(0));
 int RowsAffected = ((int)(result.ReturnValue));
 if (RowsAffected==0) {throw new ChangeConflictException();}
 return RowsAffected;
}


_________________
ASP.NET+Ajaxサンプル集 | JavaScript+Ajaxサンプル集
つと
会議室デビュー日: 2003/01/10
投稿数: 10
投稿日時: 2008-05-23 09:15
ご返信・サンプルありがとうございます。

>ストアドプロシージャをデザイナのメソッドペインにドラッグして作成したらどうでしょうか。

これはやっております(本スレッド最初の質問1行目)
ただそのストアドを呼ぶのがデザイナの作成したコードなので…


>DataContextクラスに手動でメソッドを作成するか

もしかしたらデザイナのメソッドペインにはストアドプロシージャ以外も登録できるということでしょうか?もしそうならいけそうです。
さっそく属性を調べてみます。
つと
会議室デビュー日: 2003/01/10
投稿数: 10
投稿日時: 2008-05-23 11:00
やはりデザイナのメソッドペインはメソッドの属性をみているのではなさそうです。

さらに質問ですが、Access様のサンプルにある AuthorUpdate() メソッドがSubmitChange()で呼ばれるようにするにはどうそればよいのでしょうか?

私の理解力不足で申し訳ありませんがよろしくお願いいたします。
Access
ぬし
会議室デビュー日: 2002/04/08
投稿数: 829
投稿日時: 2008-05-24 08:33
引用:

さらに質問ですが、Access様のサンプルにある AuthorUpdate() メソッドがSubmitChange()で呼ばれるようにするにはどうそればよいのでしょうか?


Scottoさんのブログに詳細手順が掲載されていますのでそちらを参照してください。

http://weblogs.asp.net/scottgu/archive/2007/08/23/linq-to-sql-part-7-updating-our-database-using-stored-procedures.aspx

以下概要です。

SPROCを呼び出すようにするには、Authorクラスのプロパティを表示して
既定のメソッドのUPDATEをSPROCに書き換えます。

それから、SPROCのメソッドをパーシャルクラスに移動させてカスタマイズします。

つまり、以下のメソッドをパーシャルクラスに貼り付けます。

コード:
[Function(Name:"dbo.UpdateAuthor")]
public int AuthorUpdate(
 [Parameter(Name="ID")] Guid ID,
 [Parameter(Name="LastName")] string lastName,
 [Parameter(Name="FirstName")] string firstName,
 [Parameter(Name="TimeStamp")] byte[] timeStamp)
{
 ...

 IExecuteResult result = this.ExecuteMethodCall(
   this, ((MethodInfo)(MethodInfo.GetCurrentMethod())),
   ID, lastName, firstName, timeStamp);
 ID = (Guid)(result.GetParameterValue(0));
 int RowsAffected = ((int)(result.ReturnValue));
 if (RowsAffected==0) {throw new ChangeConflictException();}
 return RowsAffected;
}






_________________
ASP.NET+Ajaxサンプル集 | JavaScript+Ajaxサンプル集
つと
会議室デビュー日: 2003/01/10
投稿数: 10
投稿日時: 2008-05-24 13:52
返信ありがとうございます。

Scottさんのブログは以前より参考にさせて頂いております。
そこには「一度デザイナで更新ロジックをストアド使用するよう指定し、生成されたコードをコピーしてパーシャルクラスで使いなさい」とありました。
どっとねっとふぁん様のご返信にもパーシャルメソッドを利用するとの内容でしたので、この方法しかないのかもしれません。

Access様、どっとねっとふぁん様 ありがとうございました。


以下感想ですが、正直なところ VisualStudio2008 と LINQtoSQL + ストアドプロシージャ を使用してアプリケーションを開発する際には、誰もが必ず引っかかるのではないかと思います。
調べるほどに、

・オプティミスティック同時実行に対応することの必要性を説いている
・ストアドを使用しない場合はデザイナのみでオプティミスティック同時実行に完全対応している
・更新ロジックにストアドプロシージャを使用することの必要性・利便性を説いている
・更新ロジックにストアドを使用する方法がデザイナで用意されている

にも関わらず、更新ロジックにストアドを使用してオプティミスティック同時実行に対応するにはコピーペーストなどの作業を行わなければならないとは考えにくいと思った次第です。
デザイナの更新ロジックを「ランタイムを使用」にして(でないとパーシャルメソッドが呼ばれない)いるのに自前のコードが呼ばれる事にも不安(更新処理が二度行われるのではないか)を感じます。
せめてオプティミスティック同時実行の検出に「ランタイムを使用」と同じ仕組みが採用されていたり、ストアドの戻り値を処理するようなパーシャルメソッドを呼び出すコードが生成されていればスッキリするのですが・・・


以上の事が自分の勉強不足で、整然とした手段がちゃんと用意されていることを期待して質問致しました。
せっかくのすばらしい開発ツールですので少々残念な気が致しますが、現実的な手段として受け止めたいと思います。

スキルアップ/キャリアアップ(JOB@IT)