我如何实现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中需要这种服务吗?

我如何实现DbContext连接字符串在.net核心

另一种选择是调用以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使用其他的