假设有一个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<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
}
服务类中的业务逻辑:
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();
}
}
在控制器中注入服务类
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<IUnitOfWork>().HttpContextScoped().Use(() => new Sample07Context());
x.ForRequestedType<IProductService>().TheDefaultIsConcreteType<EfProductService>();
});
//Set current Controller factory as StructureMapControllerFactory
ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
}
单个数据库的一切正常,但在我的场景中,用户可以使用多个数据库,我的意思是用户应该能够在运行时更改连接字符串。我们为用户在应用程序中创建的每个项目创建单独的数据库。
现在问题是我们将DbContext注入服务并且DbContext从web.config读取连接字符串,因此当用户更改数据库时我们无法将新的连接字符串设置为DbContext。
你有什么建议?
答案 0 :(得分:17)
根据我的经验,我在EF 6中使用了Database First
模式。当我添加DbContext
时,Entity Data Model
会生成如下所示。
public TestEntities()
: base("name=TestEntities")
{
}
TestEntities
代表App.Config中的ConnectionString
元素
<connectionStrings>
<add name="TestEntities" connectionString="..." providerName="System.Data.EntityClient" />
</connectionStrings>
但您可以将默认代码更改为以下。
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?
。请参阅MSDN EntityConnection。
希望它有所帮助。
感谢。
答案 1 :(得分:5)
默认情况下,在Entity Framework中使用的连接字符串的名称是从您DbContext
类的名称推断出来的。但是,可以将连接字符串作为构造函数参数传递:
public class MyDbContext : DbContext, IUnitOfWork
{
public MyDbContext(string connectionString)
: base(connectionString)
{
}
}
然后,您可以配置StructureMap以传入当前连接字符串,例如
For<IUnitOfWork>().Use(ctx => new MyDbContext(TheConnectionStringToUse));
这可能来自您在代码中设置的静态值,当前会话等。
答案 2 :(得分:0)
我将建议一条完全不同的道路。假设您在web.config中设置了连接字符串,您说你为什么不使用web.debug.config和web.release.config transforrms来适当地设置连接字符串?
即。在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>
和web.release.config这样
<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>
可以获得非常详尽的解释here
答案 3 :(得分:0)
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");
答案 4 :(得分:-1)
这两种方法适用于两种不同的情况:
转换适用于部署仅针对不同环境(测试,生产)进行更改的连接字符串。
在单独的文件中添加构造函数(采用连接字符串名称)以扩展部分dbcontext类的方法允许在运行时切换连接。
答案 5 :(得分:-4)
使用不同的名称在App.Config文件中添加两个不同的连接字符串。
使用重载在实体构造函数中设置当前连接字符串名称。
在代码文件
中public ASM_DBEntities()
: base("name=ASM_DBEntities")
{
}
public ASM_DBEntities(string conn)
: base("name=ASM_DBEntities1")
{
}
当我们使用object传递字符串时,则使用不同的连接字符串。