2014-10-01 58 views
2

我很抱歉發佈此問題,但我無法評論我的問題的實際解決方案,但回答爲hereThis solution也不能以相同的方式工作。實體框架 - 在運行時更改連接字符串(需要說明)

我使用該解決方案和擴展似乎工作本身除了實際更改連接。它保持與web.config文件中定義的相同。如果我刪除該連接字符串,我會收到錯誤,說EF無法找到它。

我的做法是數據庫第一(此外,它的SQL Server 2000中...)和EF版本6(基本上,最新)

所以我的問題是 - 它如何工作?

  • 我是否必須將相同的連接名稱傳遞給擴展方法,因爲它在web.config中定義,或者它應該不同嗎?

我現在的連接字符串如下所示:

<connectionStrings> 
    <add name="CATALOGEntities" connectionString="metadata=~/bin/Models\InfoModel.csdl|~/bin/Models\InfoModel.ssdl|~/bin/Models\InfoModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=SERVER;initial catalog=CATALOG;integrated security=False;User Id=admin;Password=admin123;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" /> 
</connectionStrings> 

未遂1:這是我傳遞給擴展方法是什麼:

ConnectionTools.ChangeDatabase(db, "ANOTHERCATALOG", "ANOTHERSERVER", "admin", "admin456", false, "ANOTHERCATALOGEntities"); 

未遂2:嘗試正如VDohnal所建議的那樣:

db.ChangeDatabase("ANOTHERCATALOG", "ANOTHERSERVER", "admin", "admin456", false, "ANOTHERCATALOGEntities"); 

ATTEMPT 3有:

public partial class CATALOGEntities : DbContext { 
    public CATALOGEntities(string connectionString) : base(connectionString) { } 
    public CATALOGEntities() { 
     // TODO: Complete member initialization 
     Database.SetInitializer<CATALOGEntities>(null); 
    } 
} 

未遂4:不工作,要麼(假設我有web.configsource)中定義2個連接字符串):

if (infoWhole.QueryDetails.IsCountryUK) 
{ 
    string strConn = ConfigurationManager.ConnectionStrings["CATALOGEntities"].ConnectionString; 
    db = new CATALOGEntities(strConn); 
} 
else 
{ 
    string strConn = ConfigurationManager.ConnectionStrings["CATALOGEntitiesUSA"].ConnectionString; 
    db = new CATALOGEntities(strConn); 
} 
  • 還等什麼我應該將數據源傳遞給擴展方法 - 整個DbContext或我正在使用的控制器類中定義的那個,即CATALOGEntities

這裏是擴展方法,我使用:

public static class ConnectionTools 
{ 
    // all params are optional 
    public static void ChangeDatabase(
     this CATALOGEntities source, 
     string initialCatalog = "", 
     string dataSource = "", 
     string userId = "", 
     string password = "", 
     bool integratedSecuity = false, 
     string configConnectionStringName = "") 
    /* this would be used if the 
    * connectionString name varied from 
    * the base EF class name */ 
    { 
     try 
     { 
      // use the const name if it's not null, otherwise 
      // using the convention of connection string = EF contextname 
      // grab the type name and we're done 
      var configNameEf = string.IsNullOrEmpty(configConnectionStringName) 
       ? source.GetType().Name 
       : configConnectionStringName; 

      // add a reference to System.Configuration 
      var entityCnxStringBuilder = new EntityConnectionStringBuilder 
       (System.Configuration.ConfigurationManager 
        .ConnectionStrings[configNameEf].ConnectionString); 

      // init the sqlbuilder with the full EF connectionstring cargo 
      var sqlCnxStringBuilder = new SqlConnectionStringBuilder 
       (entityCnxStringBuilder.ProviderConnectionString); 

      // only populate parameters with values if added 
      if (!string.IsNullOrEmpty(initialCatalog)) 
       sqlCnxStringBuilder.InitialCatalog = initialCatalog; 
      if (!string.IsNullOrEmpty(dataSource)) 
       sqlCnxStringBuilder.DataSource = dataSource; 
      if (!string.IsNullOrEmpty(userId)) 
       sqlCnxStringBuilder.UserID = userId; 
      if (!string.IsNullOrEmpty(password)) 
       sqlCnxStringBuilder.Password = password; 

      // set the integrated security status 
      sqlCnxStringBuilder.IntegratedSecurity = integratedSecuity; 

      // now flip the properties that were changed 
      source.Database.Connection.ConnectionString 
       = sqlCnxStringBuilder.ConnectionString; 
     } 
     catch (Exception ex) 
     { 
      // set log item if required 
     } 
    } 
} 

我的DbContext:

public partial class CATALOGEntities : DbContext 
{ 
    public CATALOGEntities() 
     : base("name=CATALOGEntities") 
    { 
    } 
} 
+0

我沒有建議exactlty你在嘗試2寫什麼,最後一個參數不應該在那裏。你調試上下文創建?至於嘗試3 - 我懷疑你可以這樣做,不用修改TT模板,因爲EF自動生成DBContext構造函數。您應該首先通過修改TT來禁用生成構造函數。嘗試4肯定會起作用 - 但不要將嘗試3與嘗試4結合在​​一起。調試嘗試4並查看連接字符串並在創建後立即測試數據庫連接。 – 2014-10-02 06:07:52

回答

0

SOLUTION:這是最終爲我工作的。

控制器類,負責訪問SQL Server:

public class FrequentlyAccessedQueries : Controller 
{ 
    private CATALOGEntities db = FrequentlyAccessedQueries.entities(); 

    public static CATALOGEntities entities() 
    { 
     QueryDetails qdetails = new QueryDetails(); 
     bool uk = qdetails.IsCountryUK; 
     if (uk) 
     { 
      return new CATALOGEntities("name=CATALOGEntitiesUK"); 
     } 
     else 
     { 
      return new CATALOGEntities("name=CATALOGEntitiesUSA"); 
     } 
    } 
} 

的DbContext類:

public partial class CATALOGEntities : DbContext 
{ 
    public CATALOGEntities(string connectionString) 
     : base(connectionString) 
    { 
    } 
} 

web.config中的條目:

<connectionStrings> 
    <add name="CATALOGEntitiesUK" connectionString="[...]" providerName="System.Data.EntityClient" /> 
    <add name="CATALOGEntitiesUSA" connectionString="[...]" providerName="System.Data.EntityClient" /> 
</connectionStrings> 
1

綜觀您鏈接到答案的代碼,所有正在正在從web.config文件讀取連接字符串,然後使用SqlConnectionStringBuilder類將連接字符串的相關部分替換爲新的詳細信息。

它不會將修改後的連接字符串寫回web.config。您可以將現有連接字符串視爲模板。

我懷疑你想要傳入與控制器相關的上下文,最後一個參數是當前連接字符串的名稱(除非它與上下文具有相同的名稱 - 在這種情況下,你可以省略它)。

當然,這將全部假設其他數據庫具有相同的模型。

+0

謝謝@Brendan。我同意你的假設,包括關於另一個具有相同模型的DB的假設。 2個數據庫之間的唯一區別是它們服務於不同的國家,因此它們中存在不同的數據,但模型保持不變。當我明確設置數據庫參數時,我的應用程序工作正常但是,它仍然不會改變連接 - 在我看來,我得到的結果完全相同。 – Donatas 2014-10-01 08:36:00

1

您必須傳遞一個已經在.config中存在的連接名或省略它。 所以這樣稱呼它:

db.ChangeDatabase("ANOTHERCATALOG", "ANOTHERSERVER", "admin", "admin456", false); 

它不會改變你的應用程序的初始配置的連接,它只是改變了你的DbContext(= CATALOGEntities)的特定存在的實例在運行時的連接。這不是你所需要的,我想 - 當你創建一個新的DbContext時,你需要調用它。

我建議你使用不同的方法。創建一個工廠,根據所選國家生成DbContext的實例。每當創建新的DbContext時使用該工廠。另一種方法是更改​​DbContext(= CATALOGEntities)類的構造函數。

+0

謝謝@VDohnal - 仍然沒有快樂。它可以工作,但不會切換到不同的SERVER/DB。 _另一種方法是改變你的DbContext(= CATALOGEntities)類的構造函數。 - 這就是我試圖避免的:)好吧,看看我是否可以按照你的建議對它進行排序。但是,如果上面的解決方案能夠工作,那將會很好。 – Donatas 2014-10-01 09:14:43

+0

您是否在創建新的DbContext後立即將它稱爲allways? – 2014-10-01 09:16:51

+0

那麼,我有'私人CATALOGEntities db = new CATALOGEntities();'在我的控制器類的頂部。我也嘗試在'if/else'聲明中實例化'CATALOGEntities db = new CATALOGEntities();',我調用'db.ChangeDatabase(...)',但結果是一樣的。 – Donatas 2014-10-01 09:24:38

0

另一種方式去改變數據庫連接是動態改變ConfigurationManager的ConnectionString。
這有點破解,但可以讓你輕鬆地通過幾個不同的數據庫(開發,測試,產品)進展。它要求您在每個連接的數據庫中都有相同的表。 如果您需要更改連接字符串中的其他內容,希望這對您而言將是一個好的開始。

string DataBaseName = "bab" 
string applicationName = Environment.GetCommandLineArgs()[0] ; 
string exePath = System.IO.Path.Combine(Environment.CurrentDirectory, applicationName); 
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); 
var connectionStringsSection = (ConnectionStringsSection)config.GetSection("connectionStrings"); 
//excuse the poor regex - I'm still figuring it out 
connectionStringsSection.ConnectionStrings["Entities"].ConnectionString = 
Regex.Replace(connectionStringsSection.ConnectionStrings["Entities"].ConnectionString, "initial catalog.*;(i)", "initial catalog ="+DataBaseName+";i"); 
config.Save(); 
ConfigurationManager.RefreshSection("connectionStrings"); 

Entities test = new Entities(); 
IEnumerable<int> list = from bobble in test.bobble 
           where bobble.ID < 250 
           select bobble.ID; 
相關問題