런타임시 Entity Framework 변경 연결
내 모델 및 DAL 어셈블리를 참조하는 웹 API 프로젝트가 있습니다. 사용자에게 다른 데이터베이스를 선택할 수있는 로그인 화면이 표시됩니다.
다음과 같이 연결 문자열을 작성합니다.
public void Connect(Database database)
{
//Build an SQL connection string
SqlConnectionStringBuilder sqlString = new SqlConnectionStringBuilder()
{
DataSource = database.Server,
InitialCatalog = database.Catalog,
UserID = database.Username,
Password = database.Password,
};
//Build an entity framework connection string
EntityConnectionStringBuilder entityString = new EntityConnectionStringBuilder()
{
Provider = database.Provider,
Metadata = Settings.Default.Metadata,
ProviderConnectionString = sqlString.ToString()
};
}
먼저 데이터 컨텍스트의 연결을 실제로 어떻게 변경합니까?
둘째, 이것은 웹 API 프로젝트이므로 연결 문자열 (위의 로그인에서 설정 됨)이 사용자의 상호 작용 동안 지속됩니까? 아니면 매번 내 데이터 컨텍스트에 전달되어야합니까?
이 답변에 조금 늦었지만 깔끔한 작은 확장 방법으로 이것을 수행하는 잠재적 인 방법이 있다고 생각합니다. 구성에 대한 EF 규칙과 약간의 프레임 워크 호출을 활용할 수 있습니다.
어쨌든, 주석이 달린 코드와 예제 사용법 :
확장 메서드 클래스 :
public static class ConnectionTools
{
// all params are optional
public static void ChangeDatabase(
this DbContext source,
string initialCatalog = "",
string dataSource = "",
string userId = "",
string password = "",
bool integratedSecuity = true,
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
}
}
}
기본 사용법 :
// assumes a connectionString name in .config of MyDbEntities
var selectedDb = new MyDbEntities();
// so only reference the changed properties
// using the object parameters by name
selectedDb.ChangeDatabase
(
initialCatalog: "name-of-another-initialcatalog",
userId: "jackthelady",
password: "nomoresecrets",
dataSource: @".\sqlexpress" // could be ip address 120.273.435.167 etc
);
이미 기본 기능을 갖추고 있지만 이것이 약간의 다양성을 추가 할 것이라고 생각했습니다.
DbContext
연결 문자열 또는 연결 문자열 자체의 이름을 허용하는 생성자 오버로드가 있습니다. 고유 한 버전을 구현하고 기본 생성자에 전달합니다.
public class MyDbContext : DbContext
{
public MyDbContext( string nameOrConnectionString )
: base( nameOrConnectionString )
{
}
}
그런 다음 구성된 연결 문자열의 이름이나 연결 문자열 자체를 인스턴스화 할 때 전달하기 만하면됩니다. DbContext
var context = new MyDbContext( "..." );
Jim Tollan의 대답은 훌륭하게 작동하지만 오류 : 키워드가 '데이터 소스'를 지원하지 않습니다. 이 문제를 해결하기 위해 그의 코드에서이 부분을 변경해야했습니다.
// add a reference to System.Configuration
var entityCnxStringBuilder = new EntityConnectionStringBuilder
(System.Configuration.ConfigurationManager
.ConnectionStrings[configNameEf].ConnectionString);
이에:
// add a reference to System.Configuration
var entityCnxStringBuilder = new EntityConnectionStringBuilder
{
ProviderConnectionString = new SqlConnectionStringBuilder(System.Configuration.ConfigurationManager
.ConnectionStrings[configNameEf].ConnectionString).ConnectionString
};
정말 죄송합니다. 다른 답변에 답변하기 위해 답변을 사용해서는 안된다는 것을 알고 있지만 답변이 너무 길어서 댓글을 작성할 수 없습니다.
생성 된 클래스는 '부분'입니다!
public partial class Database1Entities1 : DbContext
{
public Database1Entities1()
: base("name=Database1Entities1")
{
}
... 그리고 다음과 같이 부릅니다.
using (var ctx = new Database1Entities1())
{
#if DEBUG
ctx.Database.Log = Console.Write;
#endif
따라서 원래 자동 생성 된 클래스 (동일한 클래스 이름!)에 대한 부분 자체 클래스 파일을 만들고 이전에 Moho의 답변과 같이 연결 문자열 매개 변수가있는 새 생성자를 추가하면됩니다.
그 후에 원본에 대해 매개 변수화 된 생성자를 사용할 수 있습니다. :-)
예:
using (var ctx = new Database1Entities1(myOwnConnectionString))
{
#if DEBUG
ctx.Database.Log = Console.Write;
#endif
web.config 또는 app.config에 여러 연결 문자열을 추가합니다.
그런 다음 다음과 같은 문자열로 가져올 수 있습니다.
System.Configuration.ConfigurationManager.
ConnectionStrings["entityFrameworkConnection"].ConnectionString;
그런 다음 문자열을 사용하여 설정합니다.
Provider
Metadata
ProviderConnectionString
여기에 더 잘 설명되어 있습니다.
string _connString = "metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;provider=System.Data.SqlClient;provider connection string="data source=localhost;initial catalog=DATABASE;persist security info=True;user id=sa;password=YourPassword;multipleactiveresultsets=True;App=EntityFramework"";
EntityConnectionStringBuilder ecsb = new EntityConnectionStringBuilder(_connString);
ctx = new Entities(_connString);
web.config에서 연결 문자열을 가져 와서 EntityConnectionStringBuilder 생성자에서 설정하고 컨텍스트의 생성자에서 EntityConnectionStringBuilder를 인수로 사용할 수 있습니다.
사용자 이름으로 연결 문자열을 캐시합니다. 몇 가지 일반적인 방법을 사용하여 캐시에서 추가 / 검색을 처리하는 간단한 예제입니다.
private static readonly ObjectCache cache = MemoryCache.Default;
// add to cache
AddToCache<string>(username, value);
// get from cache
string value = GetFromCache<string>(username);
if (value != null)
{
// got item, do something with it.
}
else
{
// item does not exist in cache.
}
public void AddToCache<T>(string token, T item)
{
cache.Add(token, item, DateTime.Now.AddMinutes(1));
}
public T GetFromCache<T>(string cacheKey) where T : class
{
try
{
return (T)cache[cacheKey];
}
catch
{
return null;
}
}
제 경우에는 DbContext와는 반대로 ObjectContext를 사용하고 있으므로 해당 목적으로 허용되는 답변에서 코드를 수정했습니다.
public static class ConnectionTools
{
public static void ChangeDatabase(
this ObjectContext source,
string initialCatalog = "",
string dataSource = "",
string userId = "",
string password = "",
bool integratedSecuity = true,
string configConnectionStringName = "")
{
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.Connection.ConnectionString
= sqlCnxStringBuilder.ConnectionString;
}
catch (Exception ex)
{
// set log item if required
}
}
}
앱 구성에 여러 데이터 소스를 갖고 싶었습니다. 따라서 app.config에서 섹션을 설정 한 후 데이터 소스를 교체 한 다음 연결 문자열로 dbcontext에 전달합니다.
//Get the key/value connection string from app config
var sect = (NameValueCollection)ConfigurationManager.GetSection("section");
var val = sect["New DataSource"].ToString();
//Get the original connection string with the full payload
var entityCnxStringBuilder = new EntityConnectionStringBuilder(ConfigurationManager.ConnectionStrings["OriginalStringBuiltByADO.Net"].ConnectionString);
//Swap out the provider specific connection string
entityCnxStringBuilder.ProviderConnectionString = val;
//Return the payload with the change in connection string.
return entityCnxStringBuilder.ConnectionString;
알아내는 데 약간의 시간이 걸렸습니다. 누군가에게 도움이되기를 바랍니다. 나는 그것을 너무 복잡하게 만들고 있었다. 이 전에.
일반 연결 문자열을 Entity Framework 형식으로 변환하는 두 가지 확장 메서드가 있습니다. 이 버전은 app.config 파일에서 기본 프로젝트로 연결 문자열을 복사하지 않고 클래스 라이브러리 프로젝트에서 잘 작동합니다. 이것은 VB.Net이지만 C #으로 변환하기 쉽습니다.
Public Module Extensions
<Extension>
Public Function ToEntityConnectionString(ByRef sqlClientConnStr As String, ByVal modelFileName As String, Optional ByVal multipleActiceResultSet As Boolean = True)
Dim sqlb As New SqlConnectionStringBuilder(sqlClientConnStr)
Return ToEntityConnectionString(sqlb, modelFileName, multipleActiceResultSet)
End Function
<Extension>
Public Function ToEntityConnectionString(ByRef sqlClientConnStrBldr As SqlConnectionStringBuilder, ByVal modelFileName As String, Optional ByVal multipleActiceResultSet As Boolean = True)
sqlClientConnStrBldr.MultipleActiveResultSets = multipleActiceResultSet
sqlClientConnStrBldr.ApplicationName = "EntityFramework"
Dim metaData As String = "metadata=res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl;provider=System.Data.SqlClient;provider connection string='{1}'"
Return String.Format(metaData, modelFileName, sqlClientConnStrBldr.ConnectionString)
End Function
End Module
그 후 DbContext에 대한 부분 클래스를 만듭니다.
Partial Public Class DlmsDataContext
Public Shared Property ModelFileName As String = "AvrEntities" ' (AvrEntities.edmx)
Public Sub New(ByVal avrConnectionString As String)
MyBase.New(CStr(avrConnectionString.ToEntityConnectionString(ModelFileName, True)))
End Sub
End Class
쿼리 생성 :
Dim newConnectionString As String = "Data Source=.\SQLEXPRESS;Initial Catalog=DB;Persist Security Info=True;User ID=sa;Password=pass"
Using ctx As New DlmsDataContext(newConnectionString)
' ...
ctx.SaveChanges()
End Using
Linq2SQLDataClassesDataContext db = new Linq2SQLDataClassesDataContext();
var query = from p in db.SyncAudits orderby p.SyncTime descending select p;
Console.WriteLine(query.ToString());
이 코드를 사용해보십시오 ...
참고URL : https://stackoverflow.com/questions/20216147/entity-framework-change-connection-at-runtime
'development' 카테고리의 다른 글
Android : ListView의 List 항목에서 Button에 대한 onClick 이벤트를 설정하는 방법 (0) | 2020.10.23 |
---|---|
장고 추상 모델 대 일반 상속 (0) | 2020.10.23 |
테스트 대상 X에 오류가 발생했습니다 (예기치 않은 조기 종료, 작업이 부트 스트랩을 완료하지 않음-다시 시작하지 않음) (0) | 2020.10.23 |
ActiveRecord를 사용하면 after_update 중에 레코드의 이전 값을 가져올 수있는 방법이 있습니까? (0) | 2020.10.23 |
Eclipse“Link with Editor”에 해당하는 IntelliJ IDEA (0) | 2020.10.23 |