[英]Configuring DBContext in the constructor of my base repository class
解決方案啟動后,我需要實例化DBContext。 我問了這個問題 ,它表明我可以使用構造函數參數來做到這一點。
有人建議我以此為例:
var connection = @"Server=(localdb)\mssqllocaldb;Database=JobsLedgerDB;Trusted_Connection=True;ConnectRetryCount=0";
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlServer(connection);
using (var context = new BloggingContext(optionsBuilder.Options))
{
// do stuff
}
但是,我已經實現了存儲庫模式(無論是好是壞),並且鑒於我的情況已發生變化-在解決方案運行啟動后才具有連接字符串-我需要將其實現到基本存儲庫類中,並且我有點失利..
目前我有這個:
public class EntityBaseRepository<T> : IEntityBaseRepository<T> where T : class, IEntityBase, new()
{
public JobsLedgerAPIContext _context;
#region Properties
public EntityBaseRepository(JobsLedgerAPIContext context)
{
_context = context;
}
#endregion
public virtual IQueryable<T> GetAll()
{
return _context.Set<T>().AsQueryable();
}
public virtual int Count()
{
return _context.Set<T>().Count();
}
......
如何實現此更改,既要在構造函數中實例化DBContext(通過繞過在啟動時將上下文添加為服務的需要),又要用“ using”等包裝每個虛擬方法,等等。
EDIT .. Camilo指出我沒有數據庫名稱的身份。
基本情況是系統啟動(這是與該問題無關的Aurelia SPA項目),將程序包發送到瀏覽器,該瀏覽器顯示登錄屏幕。 用戶登錄。通過JWT控制器驗證用戶。在控制器中驗證之后(使用具有一個包含3個字段的表的目錄數據庫-用戶名,密碼,數據庫名稱),我使用數據庫名稱創建連接字符串,並然后實例化我的DBContext。
需要修改以下答案,因為出廠答案(有前途的答案)中有此問題發現的錯誤。.Nkosi對此錯誤做出了很好的回答。
編輯2 ..這是對以下已編輯問題的答復:
這是我的原始客戶端存儲庫,在構造函數上帶有:base(context)。
using JobsLedger.DATA.Abstract;
using JobsLedger.MODEL.Entities;
namespace JobsLedger.DATA.Repositories
{
public class ClientRepository : EntityBaseRepository<Client>, IClientRepository
{
private new JobsLedgerAPIContext _context;
public ClientRepository(JobsLedgerAPIContext context) : base(context)
{
_context = context;
}
public void RelatedSuburbEntities(Suburb _suburb)
{
_context.Entry(_suburb).Reference<State>(a => a.State).Load();
}
}
}
它具有對基類“上下文”的引用。 考慮到我仍然需要最后的“:base(context)”,我不確定如何修改它。 同樣,我在其中有一個方法也可以訪問_context,它是構造函數的一部分...
此外,我假設我不能再將服務注入控制器中,而是一旦我保護了連接字符串並將該連接字符串傳遞給服務后就對其進行了更新。
另外,鑒於我現在已經在啟動中添加了一個單例,是否需要刪除原始條目? :
services.AddDbContext<JobsLedgerAPIContext>(options => options.
UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), b => b.MigrationsAssembly("JobsLedger.API")));
如下有效地用我的單例引用替換它:
services.AddSingleton(typeof(IContextFactory <>),typeof(ContextFactory <>));
編輯
答案已被編輯整頓發現並錯誤固定的恩科西。 謝謝,@ Nkosi。
實施工廠模式。 您可以創建一個工廠,將其ContextFactory
,如下所示:
首先,定義接口。 進一步修改,刪除了connectionString參數
public interface IContextFactory<T> where T : DbContext
{
T CreateDbContext();
}
創建一個實現此接口的工廠類(根據Nkosi answer進行編輯)。 進一步修改以注入IHttpContextAccessor
public class ContextFactory<T> : IContextFactory<T> where T : DbContext
{
private readonly HttpContext _httpContext;
public ContextFactory(IHttpContextAccessor contextAccessor)
{
_httpContext = contextAccessor.HttpContext;
}
public T CreateDbContext()
{
// retreive the connectionString from the _httpContext.Items
// this is saved in the controller action method
var connectionString = (string)_httpContext.Items["connection-string"];
var optionsBuilder = new DbContextOptionsBuilder<T>();
optionsBuilder.UseSqlServer(connectionString);
return (T)Activator.CreateInstance(typeof(T), optionsBuilder.Options);
}
}
然后修改您的基本存儲庫,並保護JobsLedgerAPIContext
。 此上下文將由派生類設置。 進一步修改以刪除構造函數 。 它將使用無參數構造函數。
public class EntityBaseRepository<T> : IEntityBaseRepository<T> where T : class, IEntityBase, new()
{
protected JobsLedgerApiContext Context { get; set; }
public virtual IQueryable<T> GetAll()
{
return Context.Set<T>().AsQueryable();
}
public virtual int Count()
{
return Context.Set<T>().Count();
}
}
更改您的派生類以使用IContextFactory
。 進一步修改為使用_contextFactory.CreateDbContext()
參數少方法
IClientRepository
應該定義了SetContext
方法。
public class ClientRepository : EntityBaseRepository<Client>, IClientRepository
{
private readonly IContextFactory<JobsLedgerApiContext> _contextFactory;
public ClientRepository(IContextFactory<JobsLedgerApiContext> factory)
{
_contextFactory = factory;
}
// this method will set the protected Context property using the context
// created by the factory
public void SetContext()
{
Context = _contextFactory.CreateDbContext();
}
public void RelatedSuburbEntities(Suburb suburb)
{
Context.Entry(suburb).Reference<State>(a => a.State).Load();
}
}
在接收IClientRepository
實例的控制器中,您可以在HttpContext.Items
設置連接,該連接對請求有效。 然后, ContextFactory
使用IHttpContextAccessor
檢索此值。 然后,您只需調用_repository.SetContext();
存儲庫中的方法。
public class HomeController : Controller
{
private readonly IClientRepository _repository;
public HomeController(IClientRepository repository)
{
_repository = repository;
}
public IActionResult Index()
{
// save the connectionString in the HttpContext.Items
HttpContext.Items["connection-string"] = "test-connection";
// set the context
_repository.SetContext();
return View();
}
}
確保在ConfigureServices
中將IContextFactory注冊為開放的泛型,並按如下所示注冊Singleton,同時還注冊HttpContextAccessor和IClientRepository
services.AddHttpContextAccessor();
services.AddSingleton(typeof(IContextFactory<>), typeof(ContextFactory<>));
services.AddTransient<IClientRepository, ClientRepository>();
您可以這樣定義JobsLedgerAPIContext:
public class JobsLedgerAPIContext : DbContext
{
// public DbSet<Job> Jobs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=dotnetcore;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// may need to reflect entity classes and register them here.
base.OnModelCreating(modelBuilder);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.