9

SQL 2008 R2 11 月リリース データベースと .net 4.0 Beta 2 Azure worker ロール アプリケーションを使用します。worker ロールはデータを収集し、それを 1 つの ID 列を持つ単一の SQL テーブルに挿入します。この worker ロールのインスタンスが複数実行される可能性が高いため、SQL テーブルに Insert instead of トリガーを作成しました。トリガーは、SQL Merge 関数を使用して Upsert 機能を実行します。T-SQL を使用して、トリガー関数の代わりに挿入を正しく検証できました。既存の行が更新されている間に新しい行が挿入されました。これは私のトリガーのコードです:

Create Trigger [dbo].[trgInsteadOfInsert] on [dbo].[Cars] Instead of Insert
as
begin
set nocount On

merge into Cars as Target
using inserted as Source
on Target.id=Source.id AND target.Manufactureid=source.Manufactureid
when matched then 
update set Target.Model=Source.Model,
Target.NumDoors = Source.NumDoors,
Target.Description = Source.Description,
Target.LastUpdateTime = Source.LastUpdateTime,  
Target.EngineSize = Source.EngineSize
when not matched then
INSERT     ([Manufactureid]
       ,[Model]
       ,[NumDoors]
       ,[Description]
       ,[ID]
       ,[LastUpdateTime]
       ,[EngineSize])
 VALUES
       (Source.Manufactureid,
       Source.Model,
       Source.NumDoors,
       Source.Description,
       Source.ID,
       Source.LastUpdateTime,
       Source.EngineSize);
  End

worker ロール内では、オブジェクト モデルに Entity Framework を使用しています。SaveChanges メソッドを呼び出すと、次の例外が発生します。

OptimisticConcurrencyException
Store update, insert, or delete statement affected an unexpected number of rows (0).    Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.

これは、新しく挿入/更新された行ごとに SQL が IdentityScope を報告しないことが原因である可能性が高いと理解しています。次に、EF は、行が挿入されておらず、トランザクションが最終的にコミットされていないと考えます。

この例外を処理する最善の方法は何ですか? 多分SQLマージ関数からのOUTPUTを使用していますか?

ありがとう!-ポール

4

2 に答える 2

9

ご想像のとおり、問題は、Identity 列を含むテーブルへの挿入の直後に、Scope_identity() を選択して、Entity Framework に関連する値を入力することです。トリガーの代わりにこの 2 番目の手順が実行されず、0 行挿入エラーが発生します。

この StackOverflow スレッドで、トリガーの最後に次の行を追加することを提案する回答を見つけました(項目が一致せず、挿入が実行された場合)。

select [Id] from [dbo].[TableXXX] where @@ROWCOUNT > 0 and [Id] = scope_identity() 

これを Entity Framework 4.1 でテストしたところ、問題は解決しました。完全を期すために、作成したトリガー全体をここにコピーしました。このトリガー定義により、Address エンティティをコンテキストに追加し、context.SaveChanges() を使用してそれらを保存することで、テーブルに行を追加することができました。

ALTER TRIGGER [dbo].[CalcGeoLoc]
   ON  [dbo].[Address]
   INSTEAD OF INSERT
AS 
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT OFF;

-- Insert statements for trigger here
INSERT INTO Address (Street, Street2, City, StateProvince, PostalCode, Latitude, Longitude, GeoLoc, Name)
SELECT Street, Street2, City, StateProvince, PostalCode, Latitude, Longitude, geography::Point(Latitude, Longitude, 4326), Name 
FROM Inserted;

select AddressId from [dbo].Address where @@ROWCOUNT > 0 and AddressId = scope_identity();
END
于 2011-06-10T04:19:23.993 に答える