Entity Framework 6をコードファーストアプローチで使用し、StructureMapをIoCとして使用するASP.NET MVCアプリケーションがあると仮定します。
また、作業単位パターンを使用します。コードは次のとおりです。
ドメインクラス
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に新しい接続文字列を設定できないことです。
何を指示してるんですか?
私の経験では、EF 6でDatabase First
モードを使用しました。Entity Data Model
を追加すると、DbContext
が以下のように生成されます。
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)
{
}
...}
したがって、DB接続を取得するには2つのオプションがあります。
デフォルトを使用します。 EFは、構成ファイルで接続文字列を見つけます。
接続文字列をDbContextに渡します。
コードは次のようになります。
EntityConnection entityConn =DBConnectionHelper.BuildConnection();
using (var db = new TestEntities(entityConn.ConnectionString))
{
....
}
質問についてHow to build a EntityConnection?
。 MSDN EntityConnection をご覧ください。
お役に立てば幸いです。
ありがとう。
既定では、Entity Frameworkで使用する接続文字列の名前は、DbContext
クラスの名前から推測されます。ただし、canコンストラクターパラメーターとして接続文字列を渡します。
public class MyDbContext : DbContext, IUnitOfWork
{
public MyDbContext(string connectionString)
: base(connectionString)
{
}
}
次に、current接続文字列を渡すようにStructureMapを構成できます。
For<IUnitOfWork>().Use(ctx => new MyDbContext(TheConnectionStringToUse));
これは、コードで設定した静的な値、現在のセッションなどから発生する可能性があります。
私は完全に異なる道を提案するつもりです。 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>
非常に詳細な説明が利用可能です こちら