Reputation: 61
I have a multiple DBs with with identical schema. In my code, I would like to query one of the DBs by a parameter, which change dynamically.
Now it looks something like this:
public void saveNewUser(User user, string type)
{
if (type == "A")
{
using (var db = new AEntities())
{
db.Users.Add(user);
db.SaveChanges();
}
}
else
{
using (var db = new BEntities())
{
db.Users.Add(user);
db.SaveChanges();
}
}
}
Instead, I would like to do something like this:
public void saveNewUser(User user, string type)
{
using (var db = new GeneralEntity(type))
{
db.Users.Add(user);
db.SaveChanges();
}
}
Any good ideas?
Upvotes: 2
Views: 1731
Reputation: 61
What I was looking for is how to return the AEntity / BEntity dynamically, the objects already exists.
What I have done is this:
public class DbContextGeneral : DbContext
{
public virtual Users;
}
public class AEntity : DbContextGeneral
{
public override Users;
}
public class BEntity : DbContextGeneral
{
public override Users;
}
In order to receive the type dynamically:
private DbContextGeneral GetDBInstance(string value)
{
if (value == "A")
{
return new AEntity();
}
return new BEntity();
}
And then, finally:
using (var db = GetDBInstance(value))
{
db.Users.Add(user);
db.SaveChanges();
}
Upvotes: -1
Reputation: 5858
In my experience, I have only one DbContext to solve similar problems. I just modify the connection string at runtime. Entity Framework supports this by allowing you to call the constructor with a connection string.
I allow administrators to maintain settings as profiles, for a given model, that the application stores as a collection of encrypted SQL settings. At runtime, this list is loaded as dictionary with the profile name ("A", "B") serving as keys.
Then use the DbContext constructor that expects a connection string and pass it a built connection string based on your target db:
// the model name in the app.config connection string (any model name - Model1?)
private string BuildConnectionString(string profile)
{
// configuration would hold the collection of settings - however you prefer to provide this
var settings = configuration.GetConnectionSettings(profile);
// Build the provider connection string with configurable settings
var providerSB = new SqlConnectionStringBuilder
{
InitialCatalog = settings.InitialCatalog,
DataSource = settings.DataSource,
UserID = settings.User,
Password = settings.Password
};
var efConnection = new EntityConnectionStringBuilder();
// or the config file based connection without provider connection string
// var efConnection = new EntityConnectionStringBuilder(@"metadata=res://*/model1.csdl|res://*/model1.ssdl|res://*/model1.msl;provider=System.Data.SqlClient;");
efConnection.Provider = "System.Data.SqlClient";
efConnection.ProviderConnectionString = providerSB.ConnectionString;
// based on whether you choose to supply the app.config connection string to the constructor
efConnection.Metadata = "res://*/Model.DbEntities.csdl|res://*/Model.DbEntities.ssdl|res://*/Model.DbEntities.msl", model;
return efConnection.ToString();
}
Then in your example, you will only use one DbContext:
using (var db = new DbEntities(BuildConnectionString("A")))
{
db.Users.Add(user);
db.SaveChanges();
}
Upvotes: 2
Reputation: 62213
DbContext has method Set<TEntity> which returns a generic DbSet<TEntity>. You can use this instead of the added properties to any override of a DbContext
, ie. reference the base class DbContext
in your calling code and it will not care what the actual instance is for that DbContext
.
public class MyClass {
private DbContext _context;
public MyClass(DbContext context){
_context = context;
}
public void saveNewUser(User user)
{
_context.Set<User>.Add(user);
_context.SaveChanges();
}
}
The example above relies on DI to get the correct DbContext
instance in the constructor, it does not care which specific implementation as long as it knows about the entity User
later on when the method saveNewUser
is called (otherwise exception will be thrown). The DI framework can also handle disposing the created DbContext
or you can implement IDisposable
to MyClass
and dispose of DbContext
in the disposing method. Alternatively you can inject a DbContext
factory to create one when needed. (there are many options, just depends on your preferred framework and probably how your app is currently structured).
I assumed that you meant that the actual underlying entities are the exact same types. If this is wrong and there are also many User
types then this will not work.
Upvotes: 0
Reputation: 4517
Use something like a factory class maybe?
public void saveNewUser(User user, string type)
{
using (var db = myclass.GetGeneralEntity(type))
{
db.Users.Add(user);
db.SaveChanges();
}
}
Upvotes: 0