2016-07-26 75 views
3

我在這裏遵循的文件,而我使用SQL Server 2016(https://ef.readthedocs.io/en/latest/modeling/concurrency.htmlEF核心併發未強制執行

我添加了一個時間戳列到我的表名爲VersionCol,然後當我運行Scaffold-DbContext它將下列屬性放在我的DbContext的表實體中。

entity.Property(e => e.VersionCol) 
    .IsRequired() 
    .HasColumnType("timestamp") 
    .ValueGeneratedOnAddOrUpdate() 

它遺漏.IsConcurrencyToken()所以我補充說,對自己,但仍然沒有異常都在應該遭受併發問題的情況下拋出。它只是覆蓋數據。

有什麼我失蹤?

編輯:

我使用的一個數據庫,第一種方法(所以沒有[時間戳]或任何其他註釋),我的的DbContext被注入到一個服務,與services.AddScoped<IPoRepository, PoRepository>()在Startup.cs

配置

它在我的模型中生成一個public byte[] VersionCol { get; set; }字段,我相信這是正確的。

在我PoRepository我試圖更新我的寶有以下幾點:

public void SavePo(PoListing poListing) { 
    Po po; 

    try { 
     po = _context.Po.Where(p => p.Poid == poListing.PoId).First(); 
    } catch (ArgumentNullException) { 
     throw new ArgumentNullException("The PO does not exist."); 
    } 

    po.AssignedUserId = poListing.AssignedUserId; 
    po.VersionCol  = poListing.VersionCol; 

    _context.Entry(po).State = EntityState.Modified; 

    _context.SaveChanges(); 
} 

的PoListing本質上只是由PO的一部分,所以它只有它的一些列(它不是一個表在數據庫中),並且它在第一次生成時具有Po的VersionCol。如果PoListing具有比Po更老的VersionCol,那麼它應該給出例外。

EDIT2:

這工作,但我無法弄清楚如何使它無需使這個第二方面的工作,並且只需使用注入上下文。

public void SavePo(PoListing poListing) { 
    DbContextOptionsBuilder<TMS_1000Context> options = new DbContextOptionsBuilder<TMS_1000Context>(); 
    options.UseSqlServer("Server=DEVSQL16;Database=TMS_1000_Dev;Trusted_Connection=True;MultipleActiveResultSets=true"); 

    TMS_1000Context context1; 

    try { 
     po = _context.Po.Where(p => p.Poid == poListing.PoId).First(); 
    } catch (ArgumentNullException) { 
     throw new ArgumentNullException("The PO does not exist."); 
    } 

    using (context1 = new TMS_1000Context(options.Options)) { 
     po.AssignedUserId = poListing.AssignedUserId; 
     po.VersionCol = poListing.VersionCol; 

     context1.Update(po); 

     context1.SaveChanges(); 
    } 
} 

EDIT3:

目前這個工作。有另一種方法嗎?

public void SavePo(PoListing poListing) { 
    Po po; 

    try { 
     po = _context.Po.Where(p => p.Poid == poListing.PoId).First(); 
    } catch (ArgumentNullException) { 
     throw new ArgumentNullException("The PO does not exist."); 
    } 

    po.AssignedUserId = poListing.AssignedUserId; 

    _context.Entry(po).Property(u => u.VersionCol).OriginalValue = poListing.VersionCol; 

    _context.Update(po); 
    _context.SaveChanges(); 
} 
+1

請你告訴我們你是怎麼傳遞給DataContext的,我是說你如何更新你的實體? –

+1

你可以添加更多信息嗎?您是否將'[Timestamp]'屬性添加到您的代碼優先模型或您的DbContext的'OnModelCreating'方法中,還是嘗試使用數據庫優先方法從現有數據庫構建腳本?請張貼您的模型和DbContext代碼至少相關的'OnModelCreating' – Tseng

+0

我已經添加了更多的細節,請讓我知道如果有什麼你想看到的。 – GlacialFlames

回答

0

的原因,我相信這一切是因爲EF核心跟蹤只關心如果原來的值是相同的目前什麼是在數據庫中,如果他們不那麼當併發異常被拋出之時。

以下是我找到的3個修復程序。

  1. 更改原始值,使其與數據庫中存在的值不同。

    public void SavePo(PoListing poListing) { 
        Po po; 
    
        try { 
         po = _context.Po.Where(p => p.Poid == poListing.PoId).First(); 
        } catch (ArgumentNullException) { 
         throw new ArgumentNullException("The PO does not exist."); 
        } 
    
        po.AssignedUserId = poListing.AssignedUserId; 
    
        _context.Entry(po).Property(u => u.VersionCol).OriginalValue = poListing.VersionCol; 
    
        _context.Update(po); 
        _context.SaveChanges(); 
    } 
    
  2. 使用AsNoTracking()獲取實體。現在EF Core不會僅僅比較原始值。

    public void SavePo(PoListing poListing) { 
        Po po; 
    
        try { 
         po = _context.Po.AsNoTracking().Where(p => p.Poid == poListing.PoId).First(); 
        } catch (ArgumentNullException) { 
         throw new ArgumentNullException("The PO does not exist."); 
        } 
    
        po.AssignedUserId = poListing.AssignedUserId; 
        po.VersionCol  = poListing.VersionCol; 
    
        _context.Update(po); 
        _context.SaveChanges(); 
    } 
    
  3. 從上下文中分離實體。類似的功能修復#2

    public void SavePo(PoListing poListing) { 
        Po po; 
    
        try { 
         po = _context.Po.Where(p => p.Poid == poListing.PoId).First(); 
        } catch (ArgumentNullException) { 
         throw new ArgumentNullException("The PO does not exist."); 
        } 
    
        po.AssignedUserId = poListing.AssignedUserId; 
        po.VersionCol  = poListing.VersionCol; 
    
        _context.Entry(po).State = EntityState.Detached; 
    
        _context.Update(po); 
        _context.SaveChanges(); 
    }