2012-02-02 77 views
21

我正在嘗試將EF 4.3遷移與多個代碼優先的DbContexts結合使用。我的應用程序被分成幾個插件,它們可能有自己的DbContext關於他們的域名。應用程序應該使用一個單一的sql數據庫。EF 4.3在一個數據庫中使用多個DbContexts進行自動遷移

當我嘗試自動遷移空數據庫中的上下文時,這隻對第一個上下文成功。每個其他上下文都需要將AutomaticMigrationDataLossAllowed-Property設置爲true,然後嘗試刪除前一個表的表。

所以我的問題是:

  • 我怎麼能告訴遷移的配置只是爲了看看他們相應的上下文中定義的表後,獨自離開所有其他人?
  • 在單個數據庫中使用自動遷移處理多個DbContext的正確工作流程是什麼?

謝謝!

+0

這是一個非常有趣的問題。我想知道是否有多個上下文支持是移植用例的一部分。 – 2012-02-02 19:31:45

+2

我非常懷疑多上下文可以使用自動遷移,它旨在更新數據庫以使其看起來像上下文無論如何。您可能有更多的運氣使用手動遷移來開發插件,針對單獨的數據庫生成遷移,然後將它們全部應用於相同的數據庫。 – Betty 2012-02-04 02:11:28

+0

與此同時,我偷看了EF 4.3程序集,並且我也懷疑遷移框架能夠應對多種情況。但是我沒有想到的技術原因。使用EDM模型,您可以將其與數據庫進行比較,找到現有表格表創建或更改,並通過手動遷移給用戶保留刪除方案。 – 2012-02-05 11:39:53

回答

6

Code First Migrations假定每個數據庫只有一個遷移配置(每個配置一個上下文)。

我能想到的兩種可能的解決方案:

  1. 創建聚合背景下,包括各個方面,並參考來自您的遷移配置類這種「超級」上下文的所有實體。這樣所有的表格都將在用戶的數據庫中創建,但數據只會在他們安裝插件的數據庫中。

  2. 爲每個上下文使用不同的數據庫。如果您在上下文之間共享實體,請添加自定義遷移,並用Sql("CREATE VIEW ...")調用替換CreateTable(...)調用,以從實體的「始發」數據庫中獲取數據。

我會嘗試#1,因爲它使一切都在一個數據庫中。你可以在你的解決方案中創建一個獨立的項目來包含你的遷移和這個「超級」上下文。只需添加項目,引用所有插件的項目,創建包含所有實體的上下文,然後在此新項目上調用Enable-Migrations。在此之後,事情應該如預期般運作。

+5

我接受這個答案,不管它不是我的問題的答案。我認爲將遷移設計爲每個數據庫只有一個上下文是一個錯誤。一方面,每個具有不在上下文中使用的表的遺留數據庫都會產生問題。另一方面(即使預編譯視圖),具有大約100個不同實體的上下文的應用程序域需要很長時間才能開始。因此,將其分解爲更小的上下文是目前唯一的解決方案。 – 2012-02-11 08:18:26

+3

我原來的答案已經變得有點過時了。 EF 6.0刪除了每個數據庫一個Code First上下文的限制。事情應該在6.0和更新的版本中「正常工作」。 – bricelam 2014-01-26 23:24:17

3

我有一個工作站點使用遷移多個上下文。但是,您確實需要爲每個上下文使用單獨的數據庫,並且它們都是從項目的Migrations命名空間中的* Configuration類驅動的,因此,例如,CompanyDbContext使用CompanyConfiguration指向Company.sdf。 update-database -configurationtypename CompanyConfiguration。另一個LogDbContext使用LogConfiguration指向Log.sdf等。

鑑於此作品,您是否嘗試過創建2個上下文指向同一個數據庫並告訴模型構建器忽略其他上下文的表列表?

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Ignore<OtherContextsClass>(); 
    // more of these 
} 

由於遷移工作與模型構建器一起工作,這可能會完成這項工作。

糟糕的選擇是避免使用自動遷移,每次生成遷移,然後手動篩選並刪除不需要的語句,然後運行它們,儘管沒有任何東西阻止您創建一個查看上下文並生成的簡單工具聲明併爲您執行遷移修復程序。

+1

謝謝你的答案。但不幸的是,我無法分割數據庫。但是,你給了我一個很好的提示,即將自動化的輸出作爲手動輸出的基礎。 – 2012-02-24 07:36:22

+0

任何想法,如果它可以與多個模式(例如dbo)一起使用? – Betty 2012-02-26 08:27:35

32

這裏是你可以做什麼。很簡單。

您可以爲您的每一個方面的創造CONFIGRATION類。 例如

internal sealed class Configuration1 : DbMigrationsConfiguration<Context1>{ 
    public Configuration1(){ 
     AutomaticMigrationsEnabled = false; 
     MigrationsNamespace = "YourProject.Models.ContextNamespace1"; 
    } 
} 

internal sealed class Configuration2 : DbMigrationsConfiguration<Context2>{ 
    public Configuration2(){ 
     AutomaticMigrationsEnabled = false; 
     MigrationsNamespace = "YourProject.Models.ContextNamespace2"; 
    } 
} 

現在您添加遷移。你不需要啓用遷移,因爲你已經對2類進行了上述操作。

Add-Migration -configuration Configuration1 Context1Init 

這將爲context1創建遷移腳本。您可以再次爲其他上下文重複此操作。

Add-Migration -configuration Configuration2 Context2Init 

更新您的數據庫

Update-Database -configuration Configuration1 
Update-Database -configuration Configuration2 

這能夠以任意順序進行。除了你需要確保每次調用都是按順序調用的。

+0

完美,它說「請指定要使用的一個」,我不知道該怎麼做。謝謝! – joshcomley 2012-08-03 07:55:54

+1

當我嘗試使用Context1 – 2013-01-09 14:43:48

+2

我得到「模型支持上下文已經改變」這應該被標記爲答案!非常感謝! 爲了防止在MVC 5和EF 6 – oskar132 2013-10-02 01:20:28

0

我知道了有手動遷移工作,但你不能降級,因爲它不能在__MigrationHistory表配置之間discrimitate。如果我嘗試降級,那麼它會將來自其他配置的遷移視爲自動並且因爲我不允許數據丟失而失敗。我們只會使用它來升級,因此它適用於我們的目的。

它看起來頗有幾分ommision不過,我敢肯定它不會很難支持它提供有DbContexts之間沒有重疊。

1

好吧,我一直在努力與這一天,這裏是爲那些尋求答案的解決方案...

我假設大多數人閱讀這篇文章在這裏是因爲他們有一個大的DbContext類有很多DbSet <>屬性,加載需要很長時間。你可能想過給自己,哎呀,這是有道理的,我應該分裂的背景下,因爲我不會使用所有dbsets的一次,我只會根據我需要的情況下加載「部分」上下文它。所以你把它們分開,只是爲了發現Code First遷移不支持你的革命思維方式。

因此,您的第一步必須分割上下文,然後爲每個新上下文添加MigrationConfiguration類,您添加了與新的上下文類完全相同的連接字符串。

於是你試着運行一個新分裂上下文的一,通過做添加遷移CONTEXT1然後做更新,數據庫-Verbose ...

一切似乎都做工精細,但後來你發現,每一個後續遷移從先前的遷移中刪除了所有表,並且只從最後一次遷移中留下表。

這是因爲,目前的遷移模型預計每個數據庫單的DbContext,它必須是一個鏡子比賽。

我也試過,有人建議在這裏做這個,創建一個SuperContext,其中包含所有的Db集合。創建一個Migration Configuration類並運行它。保留部分Context類,並嘗試實例化並使用它們。 EF抱怨Backing模型已經改變。同樣,這是因爲EF會將您的部分dbcontext與您的Super Context遷移中剩餘的All-Sets上下文簽名進行比較。

這是我認爲的一個主要缺陷。

就我而言,我決定PERFORMANCE比遷移更重要。所以,我最終做的是,在我運行超級上下文並擁有所有表格後,我進入數據庫並手動刪除_MigrationHistory表。

現在,我可以實例化並使用我的部分上下文,而不用EF抱怨它。它沒有找到MigrationHistory表,只是繼續前進,讓我有一個數據庫的「部分」視圖。

當然,折衷是對模型的任何更改都必須手動傳播到數據庫,所以要小心。

它雖然爲我工作。

0

當然,解決方案應該由EntityFramework團隊進行修改,以便將API更改爲支持將_MigrationHistory表直接修改爲您選擇的表名,如_MigrationHistory_Context1,以便它可以處理獨立DbContext實體的修改。這樣,它們都被分開處理,並由開發人員來確保實體名稱不會相互衝突。

似乎有很多人分享我的觀點,認爲重複的DbContext與對實體超集的引用是一種虛假的非企業友好方式。對於基於模塊化(棱鏡或類似)的解決方案,重複的DbContext失敗慘重。

1

正如Brice上面提到的,最實際的解決方案是每個應用程序/數據庫有1個超級DbContext。

對整個應用程序只使用1個DbContext似乎是一個關鍵的技術和方法缺陷,因爲它影響模塊化等等。另外,如果您使用WCF數據服務,則每個應用程序只能使用1個DataService,因爲DataService只能映射到1個DbContext。所以這大大改變了架構。

另一方面,一個小優點是所有數據庫相關的遷移代碼都是集中的。

1

我剛剛遇到了這個問題,並意識到我將它們拆分成不同的上下文的原因純粹是將可管理塊中的相關模型分組,而不是出於任何其他技術原因。相反,我已經將我的上下文聲明爲分類,現在不同的代碼文件可以將DbSets添加到DbContext中。

這種自動遷移法術仍然有效。

0

我想讓人們知道下面的答案是對我有用的,但有一點需要注意:不要使用MigrationsNamespace行。

internal sealed class Configuration1 : DbMigrationsConfiguration<Context1>{ 
     public Configuration1(){ 
     AutomaticMigrationsEnabled = false; 
     MigrationsNamespace = "YourProject.Models.ContextNamespace1"; 
    } 
} 

internal sealed class Configuration2 : DbMigrationsConfiguration<Context2>{ 
    public Configuration2(){ 
     AutomaticMigrationsEnabled = false; 
     MigrationsNamespace = "YourProject.Models.ContextNamespace2"; 
    } 
} 

不過,我已經和定義自己的環境建立了2個數據庫,所以我發現自己得到一個錯誤說「YourProject.Models命名空間已經具備ContextNamespace1定義」。這是因爲「MigrationsNamespace =」YourProject.Models.ContextNamespace2「;」在我嘗試Init(一次在遷移Context1Init文件中,一次在之前定義的位置)後,導致在YourProjects.Models命名空間下定義了dbcontext兩次。

所以,我發現了我必須在這一點上做的是通過此處的指示,開始我的數據庫,並從頭開始遷移(幸好我沒有數據,我需要保持): http://pawel.sawicz.eu/entity-framework-reseting-migrations/

然後我將代碼更改爲不包含MigrationsNamespace行。

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

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

然後我又跑加載遷移構型配置1 Context1Init命令,並再次更新,數據庫構型配置1線(爲我的第二個方面也是如此),最後,一切似乎是現在的工作很好。

相關問題