EF Core迁移SQL Server – 如何获取数据库名称?

huangapple go评论62阅读模式
英文:

EF Core migrations SQL Server - how to get database name?

问题

我有一个使用testcontainers来启动运行SQL Server的Docker容器的xunit测试装置。

当我的测试运行时,我想使用EF Core迁移数据库 - 我可以轻松做到这一点 - 我看到迁移运行并创建了表格。
问题出在我需要修改初始迁移以运行ENABLE_BROKERALTER DATABASE语句。

这是因为我的测试正在测试与SqlDependency的交互,该交互需要为数据库打开此选项。

问题在于,在修改迁移类以执行自定义SQL作为迁移的一部分时,我无法看到如何获取当前数据库名称以形成所需的ALTER SQL。

我尝试了以下方法,但从此API获取的dbName始终为null,而且这个API不常用。

 public partial class InitialCreate : Migration
 {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
           var dbName = this.TargetModel.GetDatabaseName();
           migrationBuilder.Sql($"ALTER DATABASE {dbName} SET ENABLE_BROKER");

那么我们如何获取数据库名称?

  • EF Core 6.0
  • SQL Server Docker镜像:mcr.microsoft.com/mssql/server:2019-CU18-ubuntu-20.04
英文:

I have an xunit test fixture that uses testcontainers to spin up a docker container that is running sql server.

When my test runs, I'd like to use EF Core to migrate the database - I can do this no problem - I see the migrations run and the tables are created.
The problem comes where I need to amend the initial migration to run an Alter database statement to ENABLE_BROKER.

This is because my test is testing an interaction with SqlDependency which requires this to be switched on for the database.

The issue is that when modifying the migration class to execute custom sql as part of the migration, I cannot see how to get the current database name in order to form the required ALTER sql.

I tried the following but the dbName is always null from this API and the api isn't commonly used.

 public partial class InitialCreate : Migration
 {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
           var dbName = this.TargetModel.GetDatabaseName();
           migrationBuilder.Sql($"ALTER DATABASE {dbName} SET ENABLE_BROKER");

So how can we get the database name?

  • EF Core 6.0
  • Sql Server docker image: mcr.microsoft.com/mssql/server:2019-CU18-ubuntu-20.04

答案1

得分: 1

  1. 我已经通过几种方式解决了这个问题。

  2. 我的测试连接到 SQL Server TestContainer 的 master 数据库。这不允许使用 Alter Database Current,因为它是一个系统数据库。

  3. 我使用 ALTER DATABASE CURRENT SET ENABLE_BROKER; 来避免必须指定数据库名称作为字符串文字。

  4. 在尝试在迁移期间运行上述 ALTER 语句时,仍然会出现错误,在此处描述,但是关于单用户模式的解决方法对我不起作用。我别无选择,只能在迁移期间不运行此命令 - 相反,当我的测试运行时,我单独创建一个连接并针对数据库执行此命令,在 EF Core 迁移运行并且数据库是最新的之后,但在继续运行测试逻辑之前。

这都是一种变通方法,但如何在 EF Core 迁移中实际获取数据库名称的问题仍然存在,因此如果有人解决了这个问题,我将接受那个答案。

英文:

I have worked around this in a few ways.

  1. My test was connecting to the master database of the sql server testcontainer. This does not let you use Alter Database Current as its a system database.
  2. I use ALTER DATABASE CURRENT SET ENABLE_BROKER; to avoid having to specify the database name as string literal
  3. When trying to run the above ALTER statement during a migration, it still fails with the error described here however the workaround about single user mode didn't work for me. I had no choice but to not run this during a migration - instead when my test runs, I create a connection seperately and execute this command against the database, AFTER ef core migrations have run and the database is up to date, but before proceeding to run my test logic.

This is all a workaround but the question of how to actually get the database name within an EF Core migration still stands, so if someone figures that out I will accept that as the answer.

答案2

得分: 1

您可以尝试以下翻译:

那么我们如何获取数据库名称呢?

您不能。至少您 不应该 这样做,因为:

推荐的将迁移部署到生产数据库的方式是通过生成 SQL 脚本。

应用迁移。在生成脚本时,数据库名称将不可用。

所以 ALTER DATABASE CURRENT 是正确的答案。显然,您可以嗅探当前的 DB_NAME() 并在迁移自定义 SQL 中构建动态 SQL,但那只是不美观的做法。例如:

declare @db sysname = db_name()

declare @sql nvarchar(max) = 'alter database ' + quotename(@db) + ' set enable_broker'

exec sp_executesql @sql 

而 ALTER DATABASE CURRENT 存在的原因就是为了创建不含当前数据库名称的 DDL 脚本。

英文:

>So how can we get the database name?

You can't. At least you shouldn't because:

> The recommended way to deploy migrations to a production database is
> by generating SQL scripts.

Applying Migrations. The database name would not be available at the time the script is generated.

So ALTER DATABASE CURRENT is the correct answer. Obviously, you could sniff the current DB_NAME() and construct dynamic SQL in the migration custom SQL, but that's just ugly. EG

declare @db sysname = db_name()

declare @sql nvarchar(max) = 'alter database ' + quotename(@db) + ' set enable_broker'

exec sp_executesql @sql 

And ALTER DATABASE CURRENT exists for just this reason: to create DDL scripts that aren't littered with the name of the current database.

huangapple
  • 本文由 发表于 2023年6月22日 05:52:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/76527385.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定