usuario una tiempo que permiten obtener framework example elementos ejemplo ejecucion crear contraseña connectionstrings conexión conexion con clases cambiar cadena app c# asp.net-mvc entity-framework dependency-injection structuremap

c# - una - Entity Framework: cambiar la cadena de conexión en tiempo de ejecución



connectionstrings c# (6)

Suponiendo que exista una aplicación ASP.NET MVC que use Entity Framework 6 con el enfoque de código primero y StructureMap como IoC.
También utiliza patrón de unidad de trabajo. Aquí están los códigos:

Clase de dominio

    public class Product     {         public int Id { get; set; }         public string Name { get; set; }         public decimal Price { get; set; }              }

IUnitOfWork y 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 }

Lógica de negocios en las clases de servicio:

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();         }     }

Inyectando la clase de servicio en el controlador.

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); } }

Configuración de StructureMap que llamamos en 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()); }

Todo funciona bien con una sola base de datos, pero en mi caso, el usuario puede usar múltiples bases de datos, quiero decir que el usuario debería poder cambiar la cadena de conexión en tiempo de ejecución. Creamos una base de datos separada para cada proyecto que el usuario crea en la aplicación.
Ahora el problema es que inyectamos DbContext al servicio y DbContext lee la cadena de conexión de web.config, de modo que cuando el usuario cambia la base de datos no podemos establecer una nueva cadena de conexión a DbContext.
¿Que sugieres?


Agregue dos cadenas de conexión diferentes en el archivo App.Config usando un nombre diferente.

Establezca el nombre de la cadena de conexión actual en el Constructor de entidades utilizando Sobrecarga.

En el archivo de código

public ASM_DBEntities() : base("name=ASM_DBEntities") { } public ASM_DBEntities(string conn) : base("name=ASM_DBEntities1") { }

Cuando pasamos una cadena con un objeto, se usa una cadena de conexión diferente.


De forma predeterminada, el nombre de la cadena de conexión que se usará en Entity Framework se infiere del nombre de su clase DbContext . Sin embargo, puede pasar la cadena de conexión como un parámetro de constructor:

public class MyDbContext : DbContext, IUnitOfWork { public MyDbContext(string connectionString) : base(connectionString) { } }

Luego puede configurar StructureMap para pasar la cadena de conexión actual , por ejemplo,

For<IUnitOfWork>().Use(ctx => new MyDbContext(TheConnectionStringToUse));

Esto podría provenir de un valor estático que configuró en su código, la sesión actual, etc.


En mi experiencia, usé el modo Database First en EF 6. El DbContext se generaría como a continuación cuando agrego Entity Data Model .

public TestEntities() : base("name=TestEntities") { }

Los TestEntities representan el elemento ConnectionString en App.Config

<connectionStrings> <add name="TestEntities" connectionString="..." providerName="System.Data.EntityClient" /> </connectionStrings>

Pero puede cambiar el código predeterminado a continuación.

public partial class TestEntities : DbContext { public TestEntities() : base("name=TestEntities") { } public TestEntities(string sConnectionString) : base(sConnectionString) { } ...}

Así que tienes dos opciones para obtener conexión de base de datos.

  1. utilizando el valor predeterminado. El EF encontrará la cadena de conexión en el archivo de configuración.

  2. pasando la cadena de conexión a DbContext.

El código se ve a continuación.

EntityConnection entityConn =DBConnectionHelper.BuildConnection(); using (var db = new TestEntities(entityConn.ConnectionString)) { .... }

En cuanto a la pregunta How to build a EntityConnection? . Consulte MSDN EntityConnection .

Espero que sea de ayuda.

Gracias.


Los dos enfoques son buenos para dos situaciones diferentes:

  • La transformación es buena para implementar una cadena de conexión que solo cambia para los distintos entornos (prueba, producción).

  • El enfoque de agregar un constructor (que toma el nombre de la cadena de conexión) en un archivo separado para extender la clase parcial dbcontext permite que la conexión se cambie en tiempo de ejecución.


Voy a sugerir un camino completamente diferente. Suponiendo que tenga sus cadenas de conexión configuradas en su web.config, y usted dice que sí, ¿por qué no usaría web.debug.config y web.release.config transforrms para establecer sus cadenas de conexión de manera adecuada?

Es decir, en web.debug.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>

y un web.release.config como tal

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

Una explicación muy completa está disponible here


public partial class YourDBContextClass { // Add a constructor to allow the connection string name to be changed public YourDBContextClass(string connectionStringNameInConfig) : base("name=" + connectionStringNameInConfig) { } }

Agregue múltiples cadenas de conexión a su archivo web o app.config.

en su código de programa:

YourDBContextClass dbcontext = new YourDBContextClass("alternateconnectionstringname");