【问题标题】:How to check if database creation in LocalDB is finished如何检查 LocalDB 中的数据库创建是否完成
【发布时间】:2020-05-11 22:59:18
【问题描述】:

我在一个项目中使用 SQL Server 作为数据库以及 Entity Framework Core 3.1。对于单元测试/集成测试,我们使用 LocalDB。

为确保 LocalDB 数据库处于正确的迁移状态,我们删除并重新创建测试数据库。

这看起来像这样:

using (var sqlConnection = new SqlConnection(@"Data Source=(localdb)\MSSQLLocalDB;Integrated Security=True"))
{
    sqlConnection.Open();

    new SqlCommand("USE MASTER", sqlConnection).ExecuteNonQuery();

    try
    {
        new SqlCommand($"ALTER DATABASE [MyTestDb] SET SINGLE_USER WITH ROLLBACK IMMEDIATE", sqlConnection).ExecuteNonQuery();
        new SqlCommand($"DROP DATABASE [MyTestDb]", sqlConnection).ExecuteNonQuery();
    }
    catch (SqlException e)
    {
        // We get an error if there is no database. This happens the very first time a test gets executed on a machine
    }

    new SqlCommand($"CREATE DATABASE [MyTestDb];", sqlConnection).ExecuteNonQuery();
    new SqlCommand($"ALTER DATABASE [MyTestDb] SET ALLOW_SNAPSHOT_ISOLATION ON;", sqlConnection).ExecuteNonQuery();
    new SqlCommand($"ALTER DATABASE [MyTestDb] SET READ_COMMITTED_SNAPSHOT  ON;", sqlConnection).ExecuteNonQuery();
}

using (var creationConnection = new SqlConnection(@$"Data Source=(localdb)\MSSQLLocalDB;Integrated Security=True;Initial Catalog=MyTestDb"))
{
    creationConnection.Open(); // <-- Problematic exception here

    using (var context = new MyDbContext(/*some DbContextOptions here... */))
    {
        context.Database.Migrate();
    }
}

这将在creationConnection.Open(); 上引发异常并显示以下消息:

Microsoft.Data.SqlClient.SqlException (0x80131904):无法打开登录请求的数据库“MyTestDb”。登录失败。
用户 '' 登录失败。

如果我在两个 using 块之间添加 Thread.Sleep(10_000);,则不会抛出异常。

using (var sqlConnection = new SqlConnection(@"Data Source=(localdb)\MSSQLLocalDB;Integrated Security=True"))
{
    sqlConnection.Open();

    new SqlCommand("USE MASTER", sqlConnection).ExecuteNonQuery();

    try
    {
        new SqlCommand($"ALTER DATABASE [MyTestDb] SET SINGLE_USER WITH ROLLBACK IMMEDIATE", sqlConnection).ExecuteNonQuery();
        new SqlCommand($"DROP DATABASE [MyTestDb]", sqlConnection).ExecuteNonQuery();
    }
    catch (SqlException e)
    {
        // We get an error if there is no Database. This happens the very first time a test gets executed on a machine
    }

    new SqlCommand($"CREATE DATABASE [MyTestDb];", sqlConnection).ExecuteNonQuery();
    new SqlCommand($"ALTER DATABASE [MyTestDb] SET ALLOW_SNAPSHOT_ISOLATION ON;", sqlConnection).ExecuteNonQuery();
    new SqlCommand($"ALTER DATABASE [MyTestDb] SET READ_COMMITTED_SNAPSHOT  ON;", sqlConnection).ExecuteNonQuery();
}

Thread.Sleep(10_000); // <-- exception will NOT be thrown 

using (var creationConnection = new SqlConnection(@$"Data Source=(localdb)\MSSQLLocalDB;Integrated Security=True;Initial Catalog=MyTestDb"))
{
    creationConnection.Open(); 

    using (var context = new MyDbContext(/*some DbContextOptions here... */))
    {
        context.Database.Migrate();
    }
}

我假设数据库MyTestDb 尚未在creationConnection.Open(); 上准备好并引发错误。

有没有办法检查数据库创建是否完成?

【问题讨论】:

  • 我真的不想告诉你,但你有没有考虑过做一些事情(愚蠢的小 SQL)并检查你给出的这个错误?这是最简单的解决方案。循环打开,尝试之间延迟 1 秒或半秒。尝试/抓住直到它通过。
  • 你为什么假设数据库在 creationConnection.Open(); 时还没有准备好?这些不是异步任务——它们应该在执行前进到下一条语句时完成。
  • @TomTom 我很惭愧,但我并没有想到。你是绝对正确的。
  • @mason 我也这么认为,但我测试了它,我的 LocalDB 在创建和准备连接之间需要大约 5 秒。

标签: c# sql-server unit-testing localdb ef-core-3.1


【解决方案1】:

你可以这样做:

SELECT [collation_name] FROM sys.databases WHERE name = 'MyTestDb';

如果 collat​​ion_name 有值(不为空),则数据库在线。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-14
    • 2010-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多