我如何实现DbContext连接字符串在.net核心
本文关键字:字符串 连接 net 核心 DbContext 何实现 实现 | 更新日期: 2023-09-27 18:01:50
我的情况与此链接非常相似,或者至少我的代码相似,我正在试图找到一种方法在。net Core语法中应用相同的方法。
将连接字符串传递给代码优先的DbContext
我的具体代码如下:
public partial class CompanyFormsContext : DbContext
{
public CompanyFormsContext()
: base("name=CompanyFormsContext")
{
}
public CompanyFormsContext(string connName)
: base("name=" + connName)
{
}
...
}
我得到一个错误说:
错误CS1503参数1:无法从"字符串"转换为"Microsoft.EntityFrameworkCore"。DbContextOptions companyform。NETCoreApp, Version = v1.0
当我越过base("name=CompanyFormsContext")
或base("name=" = connName)
中的括号时。
在。net Core中实现这个功能的正确方法是什么?
编辑:我想分享一下,我在我的应用程序中有以下数据库连接信息。json文件:(但是,我在startup.cs中没有设置)
"Data": {
"CompanyFormsContext": {
"ConnectionString": "Server=(localdb)''projectsv13;Database=companyforms;Trusted_Connection=True;"
},
"CompanyFormsContextQA": {
"ConnectionString": "Server=(localdb)''projectsv13;Database=companyforms;Trusted_Connection=True;"
}
}
和我发现了以下链接在Startup.cs中添加DbContextOptions而不是在网站中注册数据存储,我想知道一个简单的protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
是否足以修复我的连接?
从链接:
services.AddEntityFramework(Configuration)
.AddSqlServer()
.AddDbContext<MyDbContext>(
options =>
options.UseSqlServer(Configuration.Get("Data:CompanyFormsContext:ConnectionString"))
);
我的Startup.cs中需要这种服务吗?
另一种选择是调用以DbContextOptions为参数的基构造函数:
public BooksContext(string connectionString) : base(GetOptions(connectionString))
{
}
private static DbContextOptions GetOptions(string connectionString)
{
return SqlServerDbContextOptionsExtensions.UseSqlServer(new DbContextOptionsBuilder(), connectionString).Options;
}
一般情况下,您将需要在启动时从配置中读取它,然后使用连接字符串为您的进程配置实体框架DbContext服务。
1)在appsettings.json中添加一行:
"DbConnectionString": "Server=s;Database=db;Trusted_Connection=True;",
2)阅读Startup.cs类中的行(在调用Startup方法来构建配置之后-因此通常在ConfigureServices方法中),像这样:
var connection = Configuration["DbConnectionString"];
3)如果使用实体框架,添加一个数据库上下文服务(MyDbContext是EF生成的上下文类)。您还需要告诉内置依赖注入如何实例化数据库上下文:
services.AddDbContext<MyDbContext>(options => options.UseSqlServer(connection));
services.AddScoped<IMyDbContext, MyDbContext>();
其中IMyDbContext是(在它的简单主义)只是一个接口,你已经从你的MyDbContext
4)现在你可以定义你的控制器为MyDbContext, DI将负责构建它,并在控制器被调用时传递它:
public MyController(IMyDbContext context)
{
_context = context // store for later use
}
IMO最佳实践:
添加到configuration.json:
"ConnectionStrings": {
"BooksContext": "Server=MyServer;Database=MyDb;Trusted_Connection=True;"
}
和初始化 section:
services.AddDbContext<BooksContext>(options => options.UseSqlServer(configuration.GetConnectionString(nameof(BooksContext))));
一个简单的方法是,只需使用optionbuilder来获取上下文:
public static MyDbContext GetMyDbContext(string databaseName)
{
var optionsBuilder = new DbContextOptionsBuilder<MyDbContext>();
optionsBuilder.UseSqlServer($@"Data Source=.'SqlExpress;Initial Catalog={databaseName};Integrated Security=True");
return new MyDbContext(optionsBuilder.Options);
}
Startup.cs for static connection
services.AddScoped<MyContext>(_ => new MyContext(Configuration.GetConnectionString("myDB")));
Table1Repository.cs for dynamic connection
using (var _context = new MyContext(@"server=....){
context.Table1....
}
MyContext.cs
public MyContext(string connectionString) : base(GetOptions(connectionString))
{
}
private static DbContextOptions GetOptions(string connectionString)
{
return SqlServerDbContextOptionsExtensions.UseSqlServer(new DbContextOptionsBuilder(), connectionString).Options;
}
所以我到处搜索解决我的问题,这是我需要动态连接到基于数据的数据库,我没有时间做连接。基本上是动态环境。我没有在URL上传递数据,也没有要附加到的可能数据库的简短列表)。所以,这是我对这个问题的解决方案。这段代码将允许您使用应用程序设置。使用占位符定义连接字符串,该占位符将在运行时由代码替换。这可以在控制器或其他你认为合适的类中完成。
我同时使用了一个静态上下文和一个动态上下文,但是你也可以只使用动态上下文。
希望有人会偶然发现这一点,并说感谢上帝…尽管很可能有人会说,这家伙疯了。不管怎样,享受吧。using System;
using System.Globalization;
using System.Linq;
using Microsoft.Extensions.Configuration;
namespace CallCenter.Repositories
{
public class TestRepository : ITestRepository
{
private readonly InsuranceContext _context;
public TestRepository(InsuranceContext context)
{
_context = context;
}
public void Add(string passedInStringWhichTellsWhatDatabaseToUse)
{
var builder = new ConfigurationBuilder().AddJsonFile("appsettings.json");
var configuration = builder.Build();
var connectionString = configuration.GetConnectionString("DefaultConnection");
var agencyContext = new AgencyContext(connectionString.Replace("Database=replacethisstring", "Database=" + passedInStringWhichTellsWhatDatabaseToUse));
var company = agencyContext.Companys.FirstOrDefault(x => x.ColumnNameInDb == "xyz");
if (company != null)
{
companyId = company.CompanyId.ToString();
}
... your other code here which could include the using the passed in _context from the injected code (or you could not have any context passed in and just use dynamic context
}
}
}
}
//The AgencyContext class would look like this:
using Microsoft.EntityFrameworkCore;
namespace CallCenter.Entities
{
public class AgencyContext : DbContext
{
public AgencyContext(string connectionString) : base(GetOptions(connectionString))
{
}
private static DbContextOptions GetOptions(string connectionString)
{
return SqlServerDbContextOptionsExtensions.UseSqlServer(new DbContextOptionsBuilder(), connectionString).Options;
}
public DbSet<Companys> Companys { get; set; }
}
}
//The startup.c IServiceProvider module has this:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.AddDbContext<InsuranceContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), b => b.UseRowNumberForPaging()));
services.AddScoped<ITestRepository , TestRepository >();
....
}
最后是应用设置。Jason文件会有这样的内容:
{
"ConnectionStrings": {
"DefaultConnection": "Server=yourservername;Database=replacethisstring;User ID=youruserid;Password=yourpassword;TrustServerCertificate=True;Trusted_Connection=False;Connection Timeout=30;Integrated Security=False;Persist Security Info=False;Encrypt=True;MultipleActiveResultSets=True;",
}
}
如果您正在寻找简单的代码较少的解决方案,这应该可以做到,只需添加另一个构造函数,静态工厂方法调用作为基类的参数:
public YourDbContext(string connectionString)
: base(new DbContextOptionsBuilder().UseSqlServer(connectionString).Options)
{
}
当连接字符串在应用设置中时,接受的答案是好的。Json文件,但在某些情况下,我们需要动态地构建连接字符串。例如,在多租户系统中。每个租户都有自己的数据库。
在这种类型的系统中,连接字符串的存储位置可以随着时间的推移而改变,例如,在最初的日子里,它可能是DB,配置文件,然后后来移动到更安全的存储
在这种情况下,您可以执行以下步骤:
1 -引入一个接口,例如IConnectionStringBuilder
。然后实现ConnectionStringBuilder。
public interface IConnectionStringBuilder
{
string TenantConnectionString(string tenantIdentifier);
}
public class ConnectionStringBuilder : IConnectionStringBuilder
{
private readonly DbConnectionStringsConfig _stringsConfig;
public ConnectionStringBuilder(DbConnectionStringsConfig stringsConfig)
{
_stringsConfig = stringsConfig;
}
public string TenantConnectionString(string tenantIdentifier)
{
return @$"Server={_stringsConfig.Server};Database={_stringsConfig.Database};Trusted_Connection=True;MultipleActiveResultSets=true;Encrypt=False;";
}
}
2 - DbConnectionStringsConfig
只是一个映射应用设置的类。
"DbConnectionStringsConfig": {
"Server": "localhost",
"Database": "MyDB",
"UserId": "DEV_USER",
"Password": "DEV_PASWORD",
}
3 -在Startup或Program.cs
中设置新类 services.AddSingleton<DbConnectionStringsConfig>(configuration.GetSection(nameof(DbConnectionStringsConfig)).Get<DbConnectionStringsConfig>());
和
services.AddTransient<IConnectionStringBuilder, ConnectionStringBuilder>();
4 -然后配置DbContext这样做:
services.AddDbContext<TenantDbContext>((s, o) =>
{
var connectionStringBuilder = s.GetService<IConnectionStringBuilder>();
// read the current tenant from HttpHeader in ITenantContext
var tenant = s.GetService<ITenantContext>()?.Tenant;
// build the connectionString for the current Tenant
var connectionString = connectionStringBuilder.TenantConnectionString(tenant?.Identifier)
?? DbConstants.DEV_DEFAULT_TENANT_CONNECTION_STRING;
o.UseSqlServer(connectionString, builder => builder.MigrationsAssembly(typeof(TenantDbContext).Assembly.FullName));
});
这个解决方案的美妙之处在于,将来每当ConnectionStrings存储的位置发生变化时,您所要做的就是实现IConnectionStringBuilder
的一个版本并交换类型,就像这样。
public class SuperSecretConnectionStringBuilder : IConnectionStringBuilder
{
...
}
services.AddTransient<IConnectionStringBuilder, SuperSecretConnectionStringBuilder>();
你甚至可以有不同类型的ConnectionStringBuilders为不同的环境,所以对于DEV, STAGING和QA你可以使用appsettings.config
文件,并为PROD使用其他的