entity framework:在运行时更改连接字符串
假设有一个ASP.NET MVC应用程序使用Entity Framework 6,代码优先方法和StructureMap作为IoC。
它还使用工作单元模式。 以下是代码:
域类
public class Product { public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } }
IUnitOfWork和DbContext:
public interface IUnitOfWork { IDbSet Set() where TEntity : class; int SaveChanges(); } public class Sample07Context : DbContext, IUnitOfWork { public DbSet Products { set; get; } #region IUnitOfWork Members public new IDbSet Set() where TEntity : class { return base.Set(); } #endregion }
服务类中的业务逻辑:
public interface IProductService { void AddNewProduct(Product product); IList GetAllProducts(); } public class ProductService : IProductService { IUnitOfWork _uow; IDbSet _products; public ProductService(IUnitOfWork uow) { _uow = uow; _products = _uow.Set(); } public void AddNewProduct(Product product) { _products.Add(product); } public IList GetAllProducts() { return _products.Include(x => x.Category).ToList(); } }
在控制器中注入服务类
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); } }
我们在app_start中调用的StructureMap配置:
private static void initStructureMap() { ObjectFactory.Initialize(x => { x.For().HttpContextScoped().Use(() => new Sample07Context()); x.ForRequestedType().TheDefaultIsConcreteType(); }); //Set current Controller factory as StructureMapControllerFactory ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory()); }
单个数据库一切正常,但在我的场景中,用户可以使用多个数据库,我的意思是用户应该能够在运行时更改连接字符串。 我们为用户在应用程序中创建的每个项目创建单独的数据库。
现在问题是我们将DbContext注入服务并且DbContext从web.config读取连接字符串,因此当用户更改数据库时,我们无法将新连接字符串设置为DbContext。
你有什么建议?
根据我的经验,我在EF 6中使用了Database First
模式。当我添加Entity Data Model
时, DbContext
将如下生成。
public TestEntities() : base("name=TestEntities") { }
TestEntities
表示TestEntities
的ConnectionString
元素
但您可以将默认代码更改为以下。
public partial class TestEntities : DbContext { public TestEntities() : base("name=TestEntities") { } public TestEntities(string sConnectionString) : base(sConnectionString) { } ...}
所以你有两个选择来获得数据库连接。
-
使用默认值。 EF将在配置文件中找到连接字符串。
-
将连接字符串传递给DbContext。
代码如下所示。
EntityConnection entityConn =DBConnectionHelper.BuildConnection(); using (var db = new TestEntities(entityConn.ConnectionString)) { .... }
至于How to build a EntityConnection?
的问题How to build a EntityConnection?
。 请参阅MSDN EntityConnection 。
希望它有所帮助。
谢谢。
默认情况下,在Entity Framework中使用的连接字符串的名称是从您的DbContext
类的名称推断出来的。 但是,您可以将连接字符串作为构造函数参数传递:
public class MyDbContext : DbContext, IUnitOfWork { public MyDbContext(string connectionString) : base(connectionString) { } }
然后,您可以配置StructureMap以传入当前连接字符串,例如
For().Use(ctx => new MyDbContext(TheConnectionStringToUse));
这可能来自您在代码中设置的静态值,当前会话等。
我将建议一条完全不同的道路。 假设您在web.config中设置了连接字符串,您说你为什么不使用web.debug.config和web.release.config transforrms来适当地设置连接字符串?
即在web.debug.config中
和web.release.config这样
这里有一个非常详尽的解释
public partial class YourDBContextClass { // Add a constructor to allow the connection string name to be changed public YourDBContextClass(string connectionStringNameInConfig) : base("name=" + connectionStringNameInConfig) { } }
将多个连接字符串添加到web或app.config文件中。
在你的程序代码中:
YourDBContextClass dbcontext = new YourDBContextClass("alternateconnectionstringname");
这两种方法适用于两种不同的情况:
-
该转换适用于部署仅针对不同环境(测试,生产)进行更改的连接字符串。
-
在单独的文件中添加构造函数(采用连接字符串名称)以扩展部分dbcontext类的方法允许在运行时切换连接。
使用不同的名称在App.Config文件中添加两个不同的连接字符串。
使用重载在实体构造函数中设置当前连接字符串名称。
在代码文件中
public ASM_DBEntities() : base("name=ASM_DBEntities") { } public ASM_DBEntities(string conn) : base("name=ASM_DBEntities1") { }
当我们用对象传递字符串然后使用不同的连接字符串。