Entity Framework: modifier la chaîne de connexion à l'exécution
en supposant qu'il y ait une ASP.NET MVC application qui utilise Entity Framework 6 avec code-first approach et StructureMap comme CIO.
Il utilise également L'Unité de modèle de travail.
Voici les codes :
Classe De Domaine
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
IUnitOfWork and DbContext:
public interface IUnitOfWork
{
IDbSet<TEntity> Set<TEntity>() where TEntity : class;
int SaveChanges();
}
public class Sample07Context : DbContext, IUnitOfWork
{
public DbSet<Product> Products { set; get; }
#region IUnitOfWork Members
public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
#endregion
}
logique d'Entreprise dans les classes de service :
public interface IProductService
{
void AddNewProduct(Product product);
IList<Product> GetAllProducts();
}
public class ProductService : IProductService
{
IUnitOfWork _uow;
IDbSet<Product> _products;
public ProductService(IUnitOfWork uow)
{
_uow = uow;
_products = _uow.Set<Product>();
}
public void AddNewProduct(Product product)
{
_products.Add(product);
}
public IList<Product> GetAllProducts()
{
return _products.Include(x => x.Category).ToList();
}
}
injection de la classe de service dans contrôleur
public class HomeController : Controller
{
private IProductService _productService;
private IUnitOfWork _uow;
public HomeController(IUnitOfWork uow, IProductService productService)
{
_productService = productService;
_uow = uow;
}
[HttpGet]
public ActionResult Index()
{
var list = _productService.GetAllProducts();
return View(list);
}
}
StructureMap Configuration que nous appelons dans app_start:
private static void initStructureMap()
{
ObjectFactory.Initialize(x =>
{
x.For<IUnitOfWork>().HttpContextScoped().Use(() => new Sample07Context());
x.ForRequestedType<IProductService>().TheDefaultIsConcreteType<EfProductService>();
});
//Set current Controller factory as StructureMapControllerFactory
ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
}
Tout fonctionne bien avec une seule base de données mais dans mon scénario l'utilisateur peut utiliser plusieurs bases de données, je veux dire que l'utilisateur devrait être capable de changer la chaîne de connexion à l'exécution. Nous créons une base de données séparée pour chaque projet que l'utilisateur crée dans l'application.
maintenant le problème est que nous injectons DbContext au service et DbContext lit la chaîne de connexion à partir de Web.config de sorte que lorsque l'utilisateur change la base de données, nous ne pouvons pas définir une nouvelle chaîne de connexion au DbContext.
Que proposez-vous?
6 réponses
D'après mon expérience, j'ai utilisé le Database First
mode EF 6. DbContext
serait généré comme ci-dessous lorsque je ajouter Entity Data Model
.
public TestEntities()
: base("name=TestEntities")
{
}
TestEntities
représentent le ConnectionString
élément de l'Application.Config
<connectionStrings>
<add name="TestEntities" connectionString="..." providerName="System.Data.EntityClient" />
</connectionStrings>
Mais vous pouvez changer le code par défaut ci-dessous.
public partial class TestEntities : DbContext
{
public TestEntities()
: base("name=TestEntities")
{
}
public TestEntities(string sConnectionString)
: base(sConnectionString)
{
}
...}
vous avez donc deux options pour obtenir la connexion DB.
en utilisant la valeur par défaut. Le FE trouvera la chaîne de connexion dans la configuration fichier.
passer la chaîne de connexion à DbContext.
le code ressemble à celui ci-dessous.
EntityConnection entityConn =DBConnectionHelper.BuildConnection();
using (var db = new TestEntities(entityConn.ConnectionString))
{
....
}
en ce qui concerne la question How to build a EntityConnection?
. Merci de voir MSDN EntityConnection.
j'Espère qu'il est utile.
Merci.
par défaut, le nom de la chaîne de connexion à utiliser dans Entity Framework est inféré du nom de vous DbContext
classe. Cependant, vous passez la chaîne de connexion comme paramètre de constructeur:
public class MyDbContext : DbContext, IUnitOfWork
{
public MyDbContext(string connectionString)
: base(connectionString)
{
}
}
alors vous pouvez configurer StructureMap pour passer dans le chaîne de connexion par exemple,
For<IUnitOfWork>().Use(ctx => new MyDbContext(TheConnectionStringToUse));
Cela pourrait venir d'une valeur statique que vous définissez dans votre code, la session en cours etc.
je vais suggérer un chemin complètement différent. En supposant que vous avez vos chaînes de connexion configurées dans votre web.config, ce que vous dites faire, pourquoi ne pas utiliser web.débogage.config et web.publier.config transforrms pour configurer vos chaînes de connexion de manière appropriée?
c'est à dire dans le web.débogage.config
<connectionStrings>
<add name="FooEntities" connectionString="metadata=res://*/;provider=System.Data.SqlClient;provider connection string="Data Source=IP,PORT\Instancename;
Initial Catalog=Foo;Persist Security Info=True;User ID=admin;Password=password;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient"/>
</connectionStrings>
et un site web.publier.config comme tel
<connectionStrings xdt:Transform="Replace">
<add name="FooEntities" connectionString="metadata=res://*/;provider=System.Data.SqlClient;provider connection string="Data Source=LIVEIP,PORT\Instancename;
Initial Catalog=Foo;Persist Security Info=True;User ID=admin;Password=password;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient"/>
</connectionStrings>
une explication très complète est disponible ici
public partial class YourDBContextClass
{
// Add a constructor to allow the connection string name to be changed
public YourDBContextClass(string connectionStringNameInConfig)
: base("name=" + connectionStringNameInConfig)
{
}
}
Ajouter plusieurs chaînes de connexion à votre site web ou app.fichier de configuration.
dans votre code de programme:
YourDBContextClass dbcontext = new YourDBContextClass("alternateconnectionstringname");
Les deux approches sont bonnes pour deux situations différentes:
la transformation est bonne pour déployer une chaîne de connexion qui ne change que pour les différents environnements (test, production).
l'approche consistant à ajouter un constructeur (qui prend le nom de la chaîne de connexion) dans un fichier séparé pour étendre la classe partielle dbcontext permet de commuter la connexion à l'exécution.
ajouter deux chaînes de connexion différentes dans App.Fichier de configuration utilisant un nom différent.
définir le nom de la chaîne de connexion courante dans le constructeur de L'entité en utilisant la surcharge.
Dans Le Fichier De Code
public ASM_DBEntities()
: base("name=ASM_DBEntities")
{
}
public ASM_DBEntities(string conn)
: base("name=ASM_DBEntities1")
{
}
lorsque nous passons une chaîne avec un objet, nous utilisons une chaîne de connexion différente.