2017-10-29 307 views
2

作爲EF 6.1到EF Core 2.0遷移的一部分,我添加了一個簡單測試來檢查併發令牌是否以同樣的方式工作。但我注意到,這取決於底層的數據庫提供者:它適用於SqlServer,但不適用於MS InMemory數據庫。使用Microsoft.EntityFrameworkCore.InMemory測試併發令牌

實體類是非常簡單的:

public class AcademicTermDate 
{ 
    public int AcademicTermDateID { get; set; } 

    public DateTime StartDate { get; set; } //but no end date, because it's derived in controcc and rederived here. 

    public bool Deleted { get; set; } 

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

創建它的代碼也簡單:

 using (var context = _factory.CreateDbContext(null)) 
     { 
      var term = new AcademicTermDate(); 
      term.StartDate = new DateTime(2001, month, 1); 
      context.AcademicTermDate.Add(term); 

      context.SaveChanges(); 
     } 

有趣的是,如果我用舊的普通的SQL服務器按下面的代碼:

public MyContext CreateDbContext(string[] args) 
    { 
     var builder = new DbContextOptionsBuilder<MyContext>(); 

     var connectionString = "server=.\\sql2012;Database=CA15;Trusted_Connection=True;"; 
     builder.UseSqlServer(connectionString); 

     return new MyContext(builder.Options); 
    } 

它按預期工作; on context.SaveChanges()我可以看到RowVersion被填充。

但是,如果我使用InMemory數據庫提供程序,它似乎很適合我的測試,我可以看到一個不同的行爲:RowVersion仍然填充空值(即根本沒有初始化)。

對於後者,工廠被定義爲:

public MyContext CreateDbContext(string[] args) 
    { 
     var builder = new DbContextOptionsBuilder<MyContext>(); 

     builder.UseInMemoryDatabase(databaseName: "InMemory"); 

     return new MyContext(builder.Options); 
    } 

我失去了InMemory分貝我應該提供任何重要的設置?這種差異看起來很奇怪,而且說實話,這很令人不安。

所有代碼的目標.NET 2.0的核心:

<PropertyGroup> 
    <OutputType>Exe</OutputType> 
    <TargetFramework>netcoreapp2.0</TargetFramework> 
</PropertyGroup> 

<ItemGroup> 
    <PackageReference Include="System.ComponentModel.Annotations" Version="4.4.0" /> 
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.0" /> 
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.0" /> 
    <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="2.0.0" /> 
    <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.0.0" /> 
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.0" /> 
</ItemGroup> 

任何幫助極大的讚賞。

+0

您是否嘗試過流暢的api來設置併發令牌? –

+0

是的,我確實: modelBuilder.Entity () \t \t .Property(p值=> p.RowVersion) \t \t .ValueGeneratedOnAddOrUpdate() \t \t .IsConcurrencyToken() \t \t; –

+0

行,前面的代碼可能是不正確的,但是這一個不起作用既不:modelBuilder.Entity () \t \t .Property(p值=> p.RowVersion) \t \t .ValueGeneratedOnAddOrUpdate() .IsRowVersion () ; –

回答

2

docsInMemory在測試上做了一個嚴重的期望管理嘗試。例如:

(InMemory)不是爲模仿關係數據庫而設計的。

,除其他事情,意味着

  • InMemory將允許你保存違反在關係數據庫參照完整性約束的數據。

  • 如果使用DefaultValueSql(串)爲模型中的屬性,這是一個關係型數據庫的API和對InMemory運行時不會有任何效果。

毫無疑問,初始化和更新RowVersion列的值可以被添加到這個列表。

然後,他們要給小費:

對於許多測試目的,這些差異並不重要。但是,如果您想測試更像真正的關係數據庫的行爲,請考慮使用SQLite內存模式。

對於它的價值,我同意第一部分,這等於:測試你知道差異無關緊要的事情。使用InMemory可能會比較方便,因爲您只需要將數據庫層用作隨後用於業務邏輯單元測試的模擬數據的快速供應商。

但我完全不同意第二條建議,使用SQLite來測試更依賴於正確數據層行爲的函數。那麼,如果SQLite是生產數據庫,那麼繼續。否則:始終對與生產數據庫相同的數據庫品牌進行集成測試。數據庫品牌和查詢提供者(將表達式轉換爲SQL的部分)之間的差異太大,使得集成測試足夠可靠。如果SQLite不支持您自己的數據庫品牌/查詢提供者所做的LINQ結構或語句或功能呢?避免他們請SQLite?我不這麼認爲。

所以我的建議是建立一個Sql Server集成測試數據庫來測試RowVersion相關的代碼。

+0

很好的答案,謝謝。這可能是我的假設是錯誤的,因爲我期望InMemory像任何其他RDBMS一樣行事;看起來差異更爲根本。缺乏已執行/缺失功能的列表確實會有所幫助,但我很不幸找到任何。 SQLite更好:https://docs.microsoft.com/en-us/ef/core/providers/sqlite/limitations。 我可以看到你的觀點,表明這可能被認爲是一個綜合測試;但是從我的角度來看(但我更傾向於數據庫),沒有正確維護時間戳是一個錯誤,而不是一個功能。 –

+0

我認爲英孚團隊不認同您的觀點。一個錯誤是不能運行*的,如所聲稱的*(不如預期*)。我非常肯定,他們永遠不會聲稱在InMemory中將支持RowVersions。 (不要告訴任何人,但我沒有看到InMemory有太多的實際用途,因爲無論我的DAL參與自動化測試,我都希望100%確定它的行爲與真實情況完全一致,我認爲理所當然地認爲集成測試花費很多時間,我更喜歡正確的速度)。 –