7

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

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ロール内に、私は、オブジェクトモデルのエンティティフレームワークを使用しています: これは私のトリガーのコードです。原因SQLは、それぞれの新しい挿入/更新された行のためのIdentityScopeをバック報告しないように、私はこれがliklyであることを理解

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. 

:私はSaveChangesメソッドを呼び出すと、私は次の例外をreceieve。次に、行は挿入されず、トランザクションは最終的にコミットされていないとEFは考えます。

この例外を処理する最適な方法は何ですか?たぶん、SQLマージ関数からOUTPUTを使用して?

ありがとうございます! -Paul

答えて

7

疑問に思ったように、Identity列のあるテーブルに挿入するとすぐに、scope_identity()が選択され、Entity Frameworkに関連付けられた値が設定されます。トリガーの代わりにこの2番目のステップが見逃され、0行の挿入エラーが発生します。

this StackOverflow threadで、トリガーの最後に次の行を追加することを提案しました(アイテムが一致せず、挿入が実行されている場合)。

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

これをEntity Framework 4.1でテストしたところ、私の問題は解決しました。私は完全性のためにトリガー作成全体をコピーしました。このトリガーのdefenitionを使って、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 
+1

そして、代わりの更新を行っている場合は、INSERT文の直前で "SET NOCOUNT OFF"を確認してから、それ以降は何も選択しないでください。 –

+0

Answer –

3

私はほぼ正確に同じシナリオを持っていた。その上にINSTEAD OF INSERTトリガーを持つビューにEntity Frameworkの駆動インサートは、その結果ました「行(0)の...予想外の数...」例外。ライアン・グロスの答えのおかげで、私はCentrePersonIDが自動inrcementingの同一性を有する、基になるテーブルのキーフィールドの名前で私のトリガーの最後に

SELECT SCOPE_IDENTITY() AS CentrePersonID; 

を追加することによって、それを修正しました。このようにして、EFは新しく挿入されたレコードのIDを発見することができます。

+0

フィールド名が大文字と小文字を区別しない場合でも、上記のフィールド名は大文字と小文字が区別され、対応するKeyプロパティと完全に一致している必要があります。 。 –

関連する問題