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?

17
demandé sur Mark Seemann 2014-03-08 14:13:06

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.

  1. en utilisant la valeur par défaut. Le FE trouvera la chaîne de connexion dans la configuration fichier.

  2. 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.

17
répondu Joe.wang 2014-10-21 07:28:06

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.

4
répondu Ben Foster 2014-03-08 10:36:29

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

0
répondu PlTaylor 2014-03-08 12:16:59
 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");
0
répondu Tom 2017-04-03 08:32:38

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.

-1
répondu Tom 2017-04-05 03:26:26

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.

-4
répondu Bhavik Patel 2016-08-25 05:13:52