Problem Using INSTEAD OF Triggers with Entity Framework

若你在使用識別資料行做為主索引鍵的資料表中,定義 INSTEAD OF INSERT 觸發程序,並透過 ObjectContext 的 SaveChanges 方法新增資料時,將會引發 OptimisticConcurrencyException,並導致整個交易復原。以下是發生例外狀況的錯誤訊息:
存放區更新、插入或刪除陳述式影響到非預期數目的資料列 (0)。這些實體載入之後可能被修改或刪除了。請重新整理 ObjectStateManager 實體。

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.

如以下範例,會依據 AdventureWorks 實體資料模型的定義,將新的實體物件附加到物件內容:
using (AdventureWorksEntities context = new AdventureWorksEntities()) 
{
context.AddToSalesReason(new SalesReason() {
Name = "Recommendation", ReasonType = "Other", ModifiedDate = DateTime.Now
});
context.SaveChanges();
}

當呼叫 SaveChanges 方法時,物件服務會產生及執行以下 SQL 命令:
exec sp_executesql N'insert [Sales].[SalesReason]([Name], [ReasonType], [ModifiedDate])
values (@0, @1, @2)
select [SalesReasonID]
from [Sales].[SalesReason]
where @@ROWCOUNT > 0 and [SalesReasonID] = scope_identity()
'
,N'@0 nvarchar(14),@1 nvarchar(5),@2 datetime2(7)'
,@0=N'Recommendation',@1=N'Other',@2='2009-11-02 15:14:54.4856524'

因為該實體物件包含識別插入的實體索引鍵,所以會在 INSERT 陳述式後,搭配使用 SCOPE_IDENTITY 函數以取得插入識別欄位中的最後一個識別值。然而,如果此資料表已定義 INSTEAD OF INSERT 觸發程序,則 SCOPE_IDENTITY 函數會因為分屬不同的範圍(Scope)而傳回 NULL 值,於是導致 SaveChanges 失敗,而復原該筆交易並擲回如前述的 OptimisticConcurrencyException 例外狀況。

要解決這個問題,你可以使用預儲程序取代 INSTEAD OF INSERT 觸發程序,然後利用實體資料模型設計工具(Entity Designer),把實體類型的修改函式對應至預存程序。或者,你也可以使用 ExecuteCommand 擴充方法來直接執行新增作業的預儲程序。


Share/Save/Bookmark

0 comments :: Problem Using INSTEAD OF Triggers with Entity Framework

張貼留言