测试Entity Framework数据库连接

69

我有一个连接到MYSQL数据库的应用程序,使用实体框架。它完美地工作着,但是我想在应用启动时添加一小段代码来测试与数据库的连接。

我有一个想法,即简单地运行一个小命令到数据库,并捕获任何异常,但是如果出现问题(例如App.Config丢失或数据库服务器停机),应用程序需要花费大量时间来运行此代码,然后抛出异常(约1分钟)。我想这是由于连接超时等原因造成的,但我已经尝试更改这些属性,但无济于事。

是否有人能够协助提供任何想法?


有一件事是要ping服务器来检查它是否正常。 - Tauseef
公共 PingReply Send( 字符串 hostNameOrAddress ) http://msdn.microsoft.com/zh-cn/library/7hzczzed.aspx - Tauseef
7个回答

59

正如@Danilo Breda所指出的,解决方法是调用DbContext.Database.Connection.Open()。

这是使用EF6测试过的。

我的实现:

    public static bool CheckConnection()
    {
        try
        {
            MyContext.Database.Connection.Open();
            MyContext.Database.Connection.Close();
        }
        catch(SqlException)
        {
            return false;
        }
        return true;
    }

1
我最喜欢这个解决方案,是的,你不应该在流程逻辑中使用异常(通常不应该)。 - Xan-Kun Clark-Davis
1
我会将这个加入到单元测试中。 - Bimal Poudel
1
我明白,如果我想确保每次与数据库交互时MySQL服务器都处于运行状态,我需要为每个操作执行if (CheckConnection()) {..}(以避免在MySQL服务器关闭的情况下出现应用程序错误)。有没有什么办法可以在更全局的层面上实现此检查?这样就不需要调用和重新调用CheckConnection()了吗? - W.M.
1
@W.M. 最好的选择是实现连接弹性,可以参考以下文章。https://www.codeproject.com/Tips/758469/Implementing-Connection-Resiliency-with-Entity-Fra - Geovani Martinez
1
这对我来说不是好的。它总是返回“ok”,即使我物理上拔掉了网络电缆,也能够连接到网络数据库。为了使其正常工作,我必须读取一个连接属性,例如ServerVersion,就像这样:Dim serverversion As String = dbBIZ.Database.Connection.ServerVersion(当然,在打开和关闭标记之间执行)通过这种方式,它尝试获取SQL服务器版本,并在数据库连接失败时失败。 - Gabriele Cozzolino

59

18
我通过将 SQL Server 中的一个数据库 "离线" 来测试了这个问题,并且 Database.Exists() 仍然返回了true。这是需要注意的一点... - Eric Tarasoff
1
最好的方法是使用mysql dll连接器并手动执行。如果您使用迁移,它将返回false,但连接是正常的! - Danilo Breda
1
这在 MS SQL 上不起作用,Exists 返回 true,而 DBSet.Load 同时引发异常。 - Sandor
1
什么是异常? - Tauseef
3
我相信上述解决方案适用于早于EF6版本的EF版本。 事实上,当该答案发布时,EF6还不存在。 感谢您发布详细信息,如果需要,我将进行审核和更新答案。 - Tauseef
显示剩余2条评论

37

在EntityFramework Core中,您可以简单地调用:Database.CanConnect();

(使用EF Core 2.2.1)

摘要: 确定数据库是否可用并且可以连接。

请注意,能够连接到数据库并不意味着它的架构创建等方面是最新的。


3
请注意,CanConnect在数据库服务器离线时不会返回false,而会抛出异常。 - Mariano Soto
@MarianoSoto 你确定吗?文档中说:“尝试连接时抛出的任何异常都会被捕获并不会传播到应用程序。” - Gregory Ledray
那时是真的:https://github.com/dotnet/efcore/issues/18355。也许现在情况不同了。 - Mariano Soto
1
它已经在 ef core 5.0 中修复了 https://github.com/dotnet/efcore/pull/18867 - user2457870

13

我在我的项目中使用这段代码:

private bool TestConnectionEF()
{
    using (var db = new SistemaContext())
    {
        db.Database.Connection.Open();

        if (db.Database.Connection.State == ConnectionState.Open)
        {
            Console.WriteLine(@"INFO: ConnectionString: " + db.Database.Connection.ConnectionString 
                     + "\n DataBase: " + db.Database.Connection.Database 
                     + "\n DataSource: " + db.Database.Connection.DataSource 
                     + "\n ServerVersion: " + db.Database.Connection.ServerVersion 
                     + "\n TimeOut: " + db.Database.Connection.ConnectionTimeout);

            db.Database.Connection.Close();

            return true;
        }

        return false;
    }
}

1
考虑到您使用了 using 块,那么 connection.close() 是必要的吗? - ComeIn
@ComeIn 如果您的上下文类在dispose方法中有一个databaseconnectionclose,那么您可以将其删除。我不知道ORM是否会这样做。对于我来说,当我打开一个连接时,我需要关闭它。如果我不打开,我就不需要关闭。 - Danilo Breda
EF会关闭底层的DBContext。除非必要,最好不要手动这样做。请参见:https://dev59.com/p4fca4cB1Zd3GeqPeRvD - ComeIn
如果你在代码中手动打开连接,EF 不会在数据库操作完成后自动关闭它。因此,如果 EF 对象被我手动打开,那么我需要手动将其关闭,以避免出现异常。 - Danilo Breda
那么我猜我们回到我的最初的问题。你真的需要显式地调用Connection.Open()吗?如果不需要,就将该调用删除。这是推荐的用法,但当然,如果你想额外增加手动处理数据库连接的麻烦,那就继续像现在这样做吧。 - ComeIn
阅读此内容以获取有关使用EF DBContext的最佳实践的更多信息:https://learn.microsoft.com/en-au/ef/ef6/fundamentals/working-with-dbcontext - ComeIn

8

我知道这是一个老问题,但以下是我给任何寻找较新实现的人的答案。

我可以使用 CanConnect 检查数据库的状态:

_database.Database.CanConnect();

# Async too
await _database.Database.CanConnectAsync(_cancellationTokenSource.Token);

我希望这也能对其他人有所帮助。干杯!


1
我使用了@Sandor的答案,并编写了一个扩展方法,以便与EntityFramework Core一起使用。
以下是代码:
using Microsoft.EntityFrameworkCore;
using System.Data.Common;

namespace TerminalInventory
{
    public static class ExtensionMethods
    {
        public static bool TestConnection(this DbContext context)
        {
            DbConnection conn = context.Database.GetDbConnection();

            try
            {
                conn.Open();   // Check the database connection

                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}

现在你只需要调用:

if (!context.TestConnection())
{
    logger.LogInformation("No database connection. Check the connection string in settings.json. {0}", configuration["connectionString"]);

    return;
}

2
既然你不在 using 块内,难道不应该在调用 open() 后关闭连接以避免不必要地保持连接打开状态吗?(参见 https://learn.microsoft.com/en-us/ef/ef6/fundamentals/connection-management#behavior-in-ef6-and-future-versions-1) - Felix K.
你需要关闭连接吗?还是保持连接开放状态就可以了? - user441365

-1

我在使用以下代码进行 MS SQL 连接。也许对 MySQL 也有用。甚至无需使用 EF 或 EF Core。

    public bool IsDbConnectionOK()
    {
        SqlConnectionStringBuilder conStr = new SqlConnectionStringBuilder
        {
            DataSource = ButtonServerName.Text,  // <-- My Form Elements
            InitialCatalog = ButtonDBName.Text, // <-- My Form Elements
            UserID = EditUserName.Text, // <-- My Form Elements
            Password = EditPassword.Text, // <-- My Form Elements
            IntegratedSecurity = false,
            ConnectTimeout = 30
        };

        string connectionstring = conStr.ToString();

        try
        {
            using (System.Data.SqlClient.SqlConnection connection = new System.Data.SqlClient.SqlConnection(connectionstring))
            {
                connection.Open();
                return true;
            }
        }
        catch (System.Data.SqlClient.SqlException ex)
        {
            MessageBox.Show(ex.Message + Environment.NewLine +
                "Error line: " + ex.LineNumber + Environment.NewLine +
                "Procedure name: " + ex.Procedure);
            return false;
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
            return false;
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接