I have a model that is created by EF6 ,by default my connection string is initialized in app.config as you can see here :
<connectionStrings>
<add name="ShirazRailwayEntities" connectionString="metadata=res://*/RailWay.csdl|res://*/RailWay.ssdl|res://*/RailWay.msl;provider=System.Data.SqlClient;provider connection string="data source=****;initial catalog=DB-Metro;user id=sa;password=****;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
I have 3 layers in my application Model ,UI ,Domain class .my connection string is initialized in 'Model' and 'UI' layers,I need to set connection string by user , i mean the connection string should be set by user.
My question :
As i said i have 2 layers that the connection string are initialized inside them ,Is it necessary to initialized both connection by user ? Or just the UI is enough ?Which connection string should be initialized ?
The next question is how can i set the connection string by user?
I have a repository layer between my EF model and UI called repository :
public class StationRepository : GenericRepository<ShirazRailWay.ShirazRailwayEntities, DomainClass.Station>
{
}
My Ui calls this repository .
best regards
how can i set the connection string by user?
The DbContext class that underlies your Entity Framework context class has a constructor that takes in a connectionString parameter. If you expose that in your context, you can pass whatever connection string you want to it at runtime.
using(var ctx = new MyContext(GetCurrentUserConnectionString())
{
...
}
As for your other questions, I didn't really understand what you're asking. If you want a better answer, please clarify.
You can initialize your dbcontext with custom connection string:
var context = new DbContext(connectionString);
update:
In your repository you can add parameter to constructor of repository that will initialize connection string for dbcontext.
Example:
public class StationRepository : GenericRepository<ShirazRailWay.ShirazRailwayEntities, DomainClass.Station>
{
public StationRepository(string connectionstring):base(connectionstring){}
}
public class GenericRepository<T1, T2>
{
protected GenericRepository(string connectionstring)
{
//initialize dbcontext using connection string
}
}
Related
I know that the default return here is the SQL Server database type, but I need the MySQL database type, the problem is to create a DbContext instance of the specified database type?
Of course, I know that it can also be created by specifying the connectionName, but the database connection string is encrypted and the string needs to be decrypted
The pseudo code is as follows:
public partial class MyDbContext : DbContext
{
static string mysqlConn = ReadConnectionString(); //Get the encrypted MySQL connection string
public MyDbContext() : base(mysqlConn)
{
// Even if I want to modify the connection string in this way, nor will it throw a connection string malformed exception
Database.Connection.ConnectionString = DecryptConnectionString(mysqlConn);
}
}
Ok, it's about what I expected, few of my questions can be answered.
Although I am not too familiar with EntityFramework, by looking at the source code of DbContext, I can almost certainly determine that this is a design flaw, it lacks a constructor like this:
Public DbContext(string connectionString, string providerName)
I had same problem and found .Net framework 4.5 needs additional attribute on DbContext class to use MySql as below
[DbConfigurationType(typeof(MySql.Data.Entity.MySqlEFConfiguration))]
public class MySqlContext : DbContext
{
...
}
I have a context which I derive my entity I have 5 databases these database are off the same scheme that I need to switch from at run time. The user would be selecting at the launch of the application which database they would be connecting to.
The database that is of the same scheme is SMBASchedulerEntities its just the catalogue name that is different
public class SourceContext : ContextBase
{
public SMBASchedulerEntities _sourceEntities = new SMBASchedulerEntities();
public SystemDa _systemDB = new SystemDa();
public void AddToPatient(Patient newPatient)
{
_sourceEntities.Patients.Add(newPatient);
SaveChanges();
}
public void AddToAppointmentTypes(AppointmentType AppointmentTypes)
{
_sourceEntities.AppointmentTypes.Add(AppointmentTypes);
SaveChanges();
}
}
As you can see there I reference the entities within my context so I would like to have a property that I can call such as changeDatabase and that it would take affect without restarting the application is that at all possible.
You can pass the name of the connection string you want to connect to, when instantiating your DbContext. First, you declare your DbContext like so:
public class SMBASchedulerEntities : DbContext
{
public SMBASchedulerEntities(string connectionString): base(connectionString)
{
}
}
You keep all your connection strings in your Web.config or App.config (depending on the type of project):
<connectionStrings>
<add name="DefaultConnection1" connectionString="server=localhost;user id=MyAppUser;password=SecretPass;database=MyDatabase1" providerName="System.Data.SqlClient" />
<add name="DefaultConnection2" connectionString="server=localhost;user id=MyAppUser;password=SecretPass;database=MyDatabase2" providerName="System.Data.SqlClient" />
<add name="DefaultConnection3" connectionString="server=localhost;user id=MyAppUser;password=SecretPass;database=MyDatabase3" providerName="System.Data.SqlClient" />
<add name="DefaultConnection4" connectionString="server=localhost;user id=MyAppUser;password=SecretPass;database=MyDatabase4" providerName="System.Data.SqlClient" />
<add name="DefaultConnection5" connectionString="server=localhost;user id=MyAppUser;password=SecretPass;database=MyDatabase5" providerName="System.Data.SqlClient" />
</connectionStrings>
Then you use it like this:
using (var db = new SMBASchedulerEntities("DefaultConnection1"))
{
// use MyDatabase1 through connection string "DefaultConnection1"
}
using (var db = new SMBASchedulerEntities("DefaultConnection2"))
{
// use MyDatabase2 through connection string "DefaultConnection2"
}
Dispose your DbContext
It's recommended to dispose the DbContext after using it. If you still want to use your idea with SourceContext, you could implement something like this:
public class SourceContext : ContextBase, IDisposable
{
public SMBASchedulerEntities _sourceEntities;
public SystemDa _systemDB = new SystemDa();
public SourceContext(string connectionString)
{
_sourceEntities = new SMBASchedulerEntities(connectionString);
}
public void AddToPatient(Patient newPatient)
{
_sourceEntities.Patients.Add(newPatient);
SaveChanges();
}
public void ChangeDatabaseTo(string connectionString)
{
if (_sourceEntities != null)
_sourceEntities.Dispose();
_sourceEntities = new SMBASchedulerEntities(connectionString);
}
public void AddToAppointmentTypes(AppointmentType AppointmentTypes)
{
_sourceEntities.AppointmentTypes.Add(AppointmentTypes);
SaveChanges();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_sourceEntities != null)
{
_sourceEntities.Dispose();
}
}
}
}
...then finally use it like this:
using(var context = new SourceContext("DefaultConnection1"))
{
context.AddPatient(patient); // add to Database1
context.ChangeDatabaseTo("DefaultConnection2");
context.AddPatient(patient); // add to Database2
context.ChangeDatabaseTo("DefaultConnection4");
context.AddPatient(patient); // add to Database4
}
By making your SourceContext an IDisposable, you have the opportunity to properly dispose the DbContext instance. Take note I took care of disposing the existing DbContext before changing it.
So, turns out the easiest way to do this is to put all of the DB names and connection strings in the appsettings.json file.
You can make it very complex, of course, but what I did was make a select drop down, let the user select the DB they want to use, then fire the onclick method to pull the connection string out of the app settings.json file, create an instance of the DBCONTEXT with that name’s connection string and use that DB context throughout whatever you need from there.
Public static class AppSettings
{
public static string GetConnectionString(string sDBinstanceName)
{
IConfigurationRoot Configuration;
IConfigurationBuilder builder = new ConfigurationBuilder().SetpathName(<wherever your appsettings.json file is>,”appsettings.json”).ReadJsonFile();
Configuration = builder.Build();
var tmpSettings = Configuration.GeyAppSettings();
string dbConstr = tmpSettings[“ConnectionStrings”][sDBinstanceName];
return dbConstr;
}
}
This is not MY snippet, but a derivative of what I found online. As it is from memory, it is not 100% correct, but I will fix it on Monday. I will update with author when I find it again(Monday).
Once you get the connection string you treat the DBCONTEXT like any other object, create it, use the tables (MEF) and whatever else you need, then destroy it correctly or let the garbage collection clean it up.
I got this working yesterday and please note: There are ZERO DBCONTEXTs registered in the Program.cs file as they are not needed.
This system is simple, lets you allow the user control to which Database they need based on a simple selection mechanism and answers the question.
At our shop we have MULTIPLE databases with exact same schema because we segregate data based on the timeframe for that data, but I can envision situations where you could use different schemas depending on the selection, we just do not do that.
For instance we have a Production and Development DB that are EXACTLY the same schema (different data) so the one DBCONTEXT is used for both in MEF.
With the method above we can let the user see the data in either at their command, it’s just getting there is a whole lot easier.
I am developing an MVC 5 application which is using 2 code first databases and 1 database first. Now I want to deploy and make it available for multiple clients to work. For that matter I want to generate my Database First Database for every new client. My database first database has 103 tables with PKs, FKs and triggers have also been built in them.
My DbContext is as follows:
public partial class MyEntities : DbContext
{
public MyEntities() : base("name=MyEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
** Here are my DbSet's **
}
Now the major concern of mine is that I also want to use MyEntities for accessing the databases for each client. Because my all controllers validations are accessing the database with that entity name as follows:
public MyEntities db = new MyEntities();
Now how could I be able to create a new database for each client and the Context name should remain same so that I don't have to change my code in Controllers? Moreover I also have to pass the InitialCatalogue name as a variable to web.config for each database.
You have to add one more constructor to your DbContext as follows :
public partial class MyEntities : DbContext
{
public MyEntities(string nameOrConnectionString)
: base(nameOrConnectionString)
{
}
}
You should add this constructor in a separate *.cs file as the previous one is auto-generated.
Also make sure the namespace should be same as the auto-generated code.
Now you can instantiate the DbContext class using the desired database's connection string from the web.config as follows :
public MyEntities db = new MyEntities(ConfigurationManager.ConnectionStrings["database1"]);
How to pass initial catalog as a variable name?
You can do this as;
<add name="MyDBContext" connectionString="metadata=res://*/model.csdl|res://*/model.ssdl|res://*/model.msl;provider=System.Data.SqlClient;provider connection string="data source=.;Initial Catalog={0};uid=sa; pwd=password;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient"/>
First of all you will overload your entities constructor as answered by sth. Now on user login you have to put their database name in a session variable. Lets call it "dbName". So now you can access it as:
var connection = System.Configuration.ConfigurationManager.ConnectionStrings["MyDBContext"].ConnectionString;
var connectionString = string.Format(connection, System.Web.HttpContext.Current.Session["dbName"].ToString());
var db = new YourEntities(connectionString);
db.Database.CreateIfNotExists();
I've spent a while on this now and have only found a workaround solution that I'd rather not do...
I have a context as shown below. Is there a programmatic way to specify the database to connect to via the constructor, and get it to use the System.Data.SQLite entity framework provider to connect to a SQLite database? This is working via the app.config (with a connectionstring called "Context"), but not via any programmatic way I can find of supplying it. I have tried using an entity connectionstring builder and that produces the following string:
provider=System.Data.SQLite;provider connection string='data
source="datafile.db"'
When the context is first queried with this string I get a message "Keyword not supported: 'provider'."
public class Context : DbContext
{
public IDbSet<Test> Tests { get; set; }
public Context()
: base("Context")
{
}
}
*Edit.
I may have solved this by implementing my own connectionfactory:
public class ConnectionFactory : IDbConnectionFactory
{
public DbConnection CreateConnection(string nameOrConnectionString)
{
return new SQLiteConnection(nameOrConnectionString);
}
}
Then setting:
Database.DefaultConnectionFactory = new ConnectionFactory();
However, it seems like there should be a built in way to do this, and also one that does not involve overriding the global default connection factory.
I'm currently trying to use the same DbContext (I have two databases, of identical structure) in my application. I'm not quite sure what I'm doing wrong, but here's my current code - hopefully it should be pretty obvious what I'm trying to do. I'm using EF Database First (which the error at the bottom seems not to suggest).
My context factory code:
public class HOLContextFactory
{
public static HOLDbEntities Create()
{
return new HOLDbEntities(); // Works
}
public static HOLDbQuoteEntities CreateQuote()
{
return new HOLDbQuoteEntities(); // Gives error
}
}
public partial class HOLDbQuoteEntities : HOLDbEntities
{
public HOLDbQuoteEntities()
: base("HOLDbQuoteEntities") // This should send "HOLDbQuoteEntities" as the base connection string?!
// Also tried "name=HOLDbQuoteEntities"
{
}
}
Web.config connection strings:
<add name="HOLDbEntities" connectionString="metadata=res://*/HOLDbContext.csdl|res://*/HOLDbContext.ssdl|res://*/HOLDbContext.msl;provider=System.Data.SqlClient;provider connection string=<connstringdetails>" providerName="System.Data.EntityClient" />
<add name="HOLDbQuoteEntities" connectionString="metadata=res://*/HOLDbContext.csdl|res://*/HOLDbContext.ssdl|res://*/HOLDbContext.msl;provider=System.Data.SqlClient;provider connection string=<connstringdetails>" providerName="System.Data.EntityClient" /> // using diff database - same structure
Error I'm getting when using "HOLDbQuoteEntities" :
Code generated using the T4 templates for Database First and Model
First development may not work correctly if used in Code First mode.
To continue using Database First or Model First ensure that the Entity
Framework connection string is specified in the config file of
executing application. To use these classes, that were generated from
Database First or Model First, with Code First add any additional
configuration using attributes or the DbModelBuilder API and then
remove the code that throws this exception**
Entity Framework needs to use the actual entities object:
public class HOLContextFactory
{
public static HOLDbEntities Create()
{
// default connection string
return new HOLDbEntities();
}
public static HOLDbEntities CreateQuote()
{
// specified connection string
return new HOLDbEntities ("HOLDbQuoteEntities");
}
}
public partial class HOLDbEntities
{
public HOLDbEntities(string connectionString)
: base(connectionString)
{
}
}
}
I've done the same thing in one of my project. I am creating my entity context using metadata=res://*/
Try this:
<add name="HOLDbEntities" connectionString="metadata=res://*/;provider=System.Data.SqlClient;provider connection string=<connstringdetails>" providerName="System.Data.EntityClient" />
<add name="HOLDbQuoteEntities" connectionString="metadata=res://*/;provider=System.Data.SqlClient;provider connection string=<connstringdetails>" providerName="System.Data.EntityClient" />