2015-06-20 43 views
1

我使用EF 6.1處理併發和我的服務更新方法看起來像這樣設定值和EF 6

public async override Task<int> UpdateAsync(Module updated) 
{ 
    var entity = await _context.Modules 
     .Where(e => e.Id == updated.Id) 
     .FirstOrDefaultAsync(); 

    // update existing values 
    _context.Entry(entity).CurrentValues.SetValues(updated); 

    // do not update 
    _context.SetModified(entity, "AddOnlyProperty", false); 

    return await base.UpdateAsync(entity); 
} 

我的基本UpdateAsync看起來像這樣

public async virtual Task<int> UpdateAsync(T updated) 
{ 
    var results = await ValidateAsync(updated); 

    if (!results.IsValid) 
    { 
     throw new ValidationException(results.Errors); 
    } 

    if (_context.GetState(updated) == EntityState.Detached) 
    { 
     _context.Set<T>().Attach(updated); 
     _context.SetState(updated, EntityState.Modified); 
    } 

    // we do not want the createdDate to change when an update is being done 
    _context.SetModified(updated, "CreatedDate", false); 
    _context.SetModified(updated, "CreatedByUserId", false); 

    return await _context.SaveChangesAsync(); 
} 

這個方法很簡單,它會將更新後的更改複製到實體中,這樣EF只會在創建SQL時應用所需的更改。

我的問題是併發不似乎工作,我會期待一個DbConcurrencyException被拋出?

這裏是我的基本模塊對象

public class Module : EntityBase, IEntityVersion, IEntityDelete 
{ 
    public long Id { get; set; } 

    public string Name { get; set; } 

    public byte[] RowVersion { get; set; } 
} 

當我和一個老執行更新我已經配置RowVersion在我Module.config文件rowVersion場,像這樣

this.Property(e => e.RowVersion) 
    .IsRowVersion(); 

現在rowVersion值,更新似乎仍然發生?我錯過了一個配置設置還是我做錯了?

應該拋出一個異常,或者我應該檢查rowVersion值是否與我自己匹配?

回答

1

您檢索記錄。

然後修改記錄。

其他人也修改記錄,並保存更改。

您再次檢索記錄,並更新值以匹配您所需的值。

您保存更改。

這裏的問題是「您再次檢索記錄」步驟。因爲你在之後這個人保存了更改,你已經獲得了新的行版本值。這是您需要跳過的步驟。

處理它的一種方法是在整個過程中使用一個Context,並將要修改的實體留在上下文中。實體框架將能夠跟蹤原始值。

處理它的另一種方法是自己跟蹤原始值。如果要保存更改,請創建一個分離的實體,將屬性設置爲原始值,將其附加到上下文,然後將屬性設置爲修改的值。


其實,思考它多一些,而不是使用的EF的併發處理,你應該能夠在這裏平凡編寫自己:

var entity = await _context.Modules 
    .Where(e => e.Id == updated.Id) 
    .FirstOrDefaultAsync(); 
if (entity == null) { 
    ... // throw exception about record not existing in the database 
} 
if (BitConverter.ToInt64(entity.RowVersion, 0) != BitConverter.ToInt64(updated.RowVersion, 0)) { 
    ... // throw exception about record having been updated in the database 
} 
... // your existing code to update the entity can go here 
+0

但如果我檢索實體,並覆蓋它的值行版本肯定會被覆蓋,因此它應該使用這個值來檢查它是否是最新版本?或者是你說,因爲我從數據庫檢索它,實體框架認爲它應該是最新版本無論如何,並忽略它? – Gillardo

+0

你能告訴我一個如何跟蹤變化的例子嗎?只有這樣做才能修改已更改的屬性 – Gillardo

+0

@ user2736022實體框架使用更改跟蹤,併爲所有屬性保留舊值和新值(如果實體未更改,則舊值和新值相同)。它使用行版本的舊值進行併發檢查,並忽略您嘗試給出的任何新值。在你的情況下,EF看作舊值的值實際上並不是你希望用於併發檢查的舊值。 – hvd