2013-10-17 47 views
14

遷移到Entity Framework 6後,在構建服務器上執行單元測試時出現錯誤。DropCreateDatabaseIfModelChanges EF6導致System.InvalidOperationException:支持上下文的模型已更改

我正在使用DropCreateDatabaseIfModelChanges初始值設定項。當我將其更改爲MigrateDatabaseToLatestVersion一切正常時,但我想堅持使用前者的初始化程序。

我得到的錯誤是:

System.InvalidOperationException信息:System.InvalidOperationException: 自 數據庫創建模型靠山 'AppContext' 已經時過境遷。考慮使用代碼首先遷移到更新 數據庫(http://go.microsoft.com/fwlink/?LinkId=238269)..

哪個是正確的,它改變,但DropCreateDatabaseIfModelChanges初始化,就應該重新創建。有任何想法嗎?

EF在App.config中配置。下面是相關的部分:

<connectionStrings> 
    <add name="AppContext" connectionString="Data Source=(localdb)\v11.0;Initial Catalog=my.app.unittest;Integrated Security=True" providerName="System.Data.SqlClient" /> 
</connectionStrings> 
<entityFramework> 
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework"> 
     <parameters> 
      <parameter value="v11.0" /> 
     </parameters> 
    </defaultConnectionFactory> 
    <contexts> 
     <context type="my.app.core.Data.AppContext, my.app.core"> 
      <databaseInitializer type="System.Data.Entity.DropCreateDatabaseIfModelChanges`1[[my.app.core.Data.AppContext, my.app.core]], EntityFramework" /> 
     </context> 
    </contexts> 
    <providers> 
     <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" /> 
    </providers> 
</entityFramework> 
+0

編寫數據庫配置的代碼以及如何初始化數據庫。 –

+0

我更新了配置信息的問題。希望它已經足夠了 – Chris

+0

如果您將其更改爲DropCreateDatabaseAlways其工作? –

回答

3

這是投擲,因爲你必須啓用遷移和你正在使用的DropCreateDatabaseIfModelChanges初始化。實體框架不支持在遷移時使用此初始化程序。剛剛升級到EF6後

  • 禁用初始化

  • 禁用遷移通過刪除遷移配置
5

我發現了同樣的問題:你有兩個選擇。閱讀Stefan's評論並具有相同的症狀,他描述後(試驗加載從我的主項目配置類)在我的情況

解決方案/解決方法是

  • 建立在我的測試中新class TestContext: MyDataContext項目
  • 變化從DropCreateDatabaseAlways<MyDataContext>DropCreateDatabaseAlways<TestContext>
  • 更新的初始化器/概括,我創造了我真正上下文中使用測試的地方之一

我可以這樣做,因爲我的大多數測試只是從PersistenceTest類擴展,所以我明白,如果你有一個大目錄,這可能是一個痛苦的改變。因此,期待着其他的解決方案

18

嗯,它看起來像EF 6.0引入了一個新的規則:

「如果的DbContext使用的初始化函數和遷移配置,構建模型時拋出一個異常」。

直至幷包括EF 6 RC,這並未強制執行。煩人的部分是「遷移配置」是由DbMigrationsConfiguration的實現定義的。似乎沒有辦法以編程方式在測試中禁用遷移 - 如果您實施了

我以與Sebastian Piu非常相似的方式解決它 - 我不得不從我的測試中刪除配置類,但我不能刪除它,因爲我們正在爲我們的主項目使用遷移。哎呀!

這是我的代碼之前:

public class MyDbContext : DbDContext, IMyDbContext 
{ 
    public IDbSet<Users> Users {get; set;} 
    public IDbSet<Widgets> Widgets {get; set;} 
} 

// Migrations are considered configured for MyDbContext because this class implementation exists. 
internal sealed class Configuration : DbMigrationsConfiguration<MyDbContext> 
{ 
    public Configuration() 
    { 
    AutomaticMigrationsEnabled = false; 
    } 
} 

// Declaring (and elsewhere registering) this DB initializer of type MyDbContext - but a DbMigrationsConfiguration already exists for that type. 
public class TestDatabaseInitializer : DropCreateDatabaseAlways<MyDbContext> 
{ 
    protected override void Seed(MyDbContext context) { } 
} 

我遇到System.InvalidOperationException時的DbContext在我的測試代碼被初始化。由於該應用程序不使用任何初始化程序,因此運行應用程序沒有像以前那樣出現問題。這隻會打破我的測試。

將溶液(它感覺更像是一個解決方法,以從事EF丟失)是段初始化和DbMigrationsConfiguration因此只有一個在運行時環境能夠被看見。我想我的測試使用初始化程序,我希望我的應用程序使用DbMigrationsConfiguration。如果DbContext有一個接口,這可以更乾淨地完成,但它只實現IObjectContextAdapter。

首先,我做了我的DbContext摘要:

public abstract class MyDbContextBase : DbContext, IMyDbContext 
{ 
     public IDbSet<Users> Users {get; set;} 
     public IDbSet<Widgets> Widgets {get; set;} 
} 

然後我得到的2類:

public class MyDbContext : MyDbContextBase 
{ 
    public MyDbContext(string connectionStringOrName, IDatabaseInitializer<MyDbContext> dbInitializer) 
    : base(connectionStringOrName) 
    { 
    } 
} 

public class MyTestDbContext : MyDbContextBase 
{ 
    public MyTestDbContext(string connectionStringOrName, IDatabaseInitializer<MyDbContext> dbInitializer) 
    : base(connectionStringOrName) 
    { 
    Database.SetInitializer(dbInitializer); 
    } 
} 

既是一個MyDbContext和MyTestDbContext被IMyDbContexts,所以現有的依賴注入的設置應該不需要工作變化。我只測試Spring.NET。

我DbMigrationsConfiguration實現派生類型未使用的測試:

internal sealed class Configuration : DbMigrationsConfiguration<MyDbContext> 
{ 
    public Configuration() 
    { 
    AutomaticMigrationsEnabled = false; 
    } 
} 

最後,初始化的類型被轉移到派生測試類類型:

public class TestDatabaseInitializer : DropCreateDatabaseAlways<MyTestDbContext> 
{ 
    protected override void Seed(MyTestDbContext context) { } 
} 

我可以確認我的測試正在通過,我的應用程序(和Migrations)仍然像以前一樣工作。

+1

我想知道這個工作對我來說是如何工作的,Database.SetInitializer(dbInitializer);是靜態的,因此我無法遵循這個過程。有任何想法嗎? – Kjellski

+0

這是正確的,SetInitializer是System.Data.Entity.Database(http://msdn.microsoft.com/en-us/library/gg679461(v=vs.113).aspx)上的靜態方法。什麼部分不適合你? –

+0

謝謝,保存了我的一週。試了一下其他的PostgreSQL。在SqlServer上,我對EF6數據庫初始化的默認方案沒有任何問題。 –

2

看起來這種行爲是有意的。下面是從開發商之一報價:

行爲的這種變化是由設計,因爲EF5將不使用規定的遷移意味着由初始創建的數據庫可能是由遷移創建一個不同的創建數據庫。這可能導致針對一個數據庫模式進行測試,但針對不同的數據庫模式在生產環境中運行。然而,我們已經初步決定做出改變這種行爲,這是正在這裏追蹤:https://entityframework.codeplex.com/workitem/1709

1

什麼工作正常,我是用define排除遷移。這裏是如何:

  • 創建一個名爲Test新的配置,它定義TEST
  • 在您的測試,如果沒有定義TEST拋出一個錯誤。
  • 排除你遷移時被定義TEST
#if !TEST 
internal sealed class Configuration : DbMigrationsConfiguration<Context> 
{ 
    //... 
} 
#endif 

您可能需要排除所有的遷移,這是不完全令人滿意的任一(但因爲我不我還沒有嘗試過還沒有任何遷移)。

相關問題