2015-06-02 47 views
0

我試圖爲EF實現樂觀鎖定模型。我正在嘗試使用表格上的時間戳數據類型的列。無法獲取實體框架來生成DbUpdateConcurrencyException(數據庫優先)

我試着通過修改T4腳本在成員上添加Timestamp屬性。運行我的測試,看到它不工作,然後我嘗試以相同的方式(通過T4)在同一成員上添加ConcurrencyCheck屬性。但是,在任何情況下,生成的SQL都不會在更新中使用該成員(如下所示)。我還設置了Concurrency ModeFixed EDMX設計師的財產。

我可以在更新後的獨立select中看到timestamp列,但不是更新本身。我試過打破SaveChanges(),更改數據庫記錄並在手動更新後看到時間戳記值發生變化,執行SaveChanges()行,並且執行正常,但不會引發異常。有什麼我錯過了,是否需要推出自己的時間戳比較代碼,還是我需要進入EF攔截器的世界來更改SQL輸出?謝謝。

生成的SQL:(通過DbContext.Database.Log登錄)T4後一代成員的

UPDATE [dbo].[Foo] 
SET [FooTitle] = @0 
WHERE ([FooId] = @1) 
SELECT [fooversion] 
FROM [dbo].[Foo] 
WHERE @@ROWCOUNT > 0 AND [FooId] = @1 

的最終版本:

[Timestamp] 
[ConcurrencyCheck] 
public byte[] fooversion { get; set; } 

我試圖讓EF做:

UPDATE [dbo].[Foo] 
SET [FooTitle] = @0 
WHERE ([FooId] = @1 AND [fooversion] = @2) 

回答

0

我決定推出我自己的檢查代碼。它非常高效,但它確實需要兩次到數據庫。

我寫了一個接口,該接口附加到我已經用於將事物附加到我的實體的一系列部分類。它定義了一個查找選擇器,我的實體基類服務可以使用它來獲取特定版本。沒有結果?返回消息。如果有結果,那麼該實體會按照您的預期進行更新。

接口:

public interface IVersionableDbObject<TEntity> 
    where TEntity : class, IValidatableObject 
{ 
    byte[] Version { get; } 
    Expression<Func<TEntity, bool>> LookupSelector { get; } 
} 

一個實施的例子:

public partial class Foo : IVersionableDbObject<Foo> 
{ 
    public byte[] Version { get { return fooversion; } } 

    public Expression<Func<Foo, bool>> LookupSelector 
    { 
     get { return foo => foo.FooId == FooId && foo.fooversion == Version; } 
    } 
} 

在基服務的檢查代碼:

IVersionableDbObject<TEntity> versionableSource = entity as IVersionableDbObject<TEntity>; 
if (versionableSource != null) 
{ 
    bool versionExists = innerContext.Set<TEntity>().Where(versionableSource.LookupSelector).Any(); 

    if (!versionExists) 
     return new ValidationResult(string.Format(FooResources.EntityUpdateVersionConflictError, 
        BitConverter.ToInt32(versionableSource.Version, 0))); 
} 

驗證結果僅僅是一個消息,其是一個格式化程序接受試圖查找的版本。 ValidationResult的返回是特定於我自己的實現。如果你使用它,就照你的方式去做。

下面是對.Any()生成的SQL:

SELECT 
CASE WHEN (EXISTS (SELECT 
    1 AS [C1] 
    FROM [dbo].[Foo] AS [Extent1] 
    WHERE ([Extent1].[FooId] = @p__linq__0) AND ([Extent1].[fooversion] = @p__linq__1) 
)) THEN cast(1 as bit) ELSE cast(0 as bit) END AS [C1] 
FROM (SELECT 1 AS X) AS [SingleRowTable1] 

有趣的是,當更新實際發生時,EF仍刷新行版本,而不TimestampConcurrencyCheck屬性類似我張貼在OP的SQL。

相關問題