.NET Core EF,清理 SqlConnection.CreateCommand

Har*_*ngh 9 c# entity-framework entity-framework-core .net-core asp.net-core

我正在使用 .NET Core DI 来获取,DbContext并且在我的逻辑中,我还需要在 DB 上执行原始 SQL 命令,因此为此我创建DbCommand以执行这样的 SQL(只是一个示例查询,实际查询有点复杂,所以不写在这里为简单起见):

public string GetId()
{
    var cmd = _context.Database.GetDbConnection().CreateCommand();

    bool isOpen = cmd.Connection.State == ConnectionState.Open;
    if (!isOpen)
    {
         cmd.Connection.Open();
    }

    cmd.CommandText = "Select TOP 1 ID from ABC;";
    var result = (string)cmd.ExecuteScalar();

    if (isOpen)
    {
         cmd.Connection.Close();
    }

    return result;
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,我在 DbContext 上使用GetDbConnection()CreateCommand(),所以我是否需要显式处理任何这些命令的结果(或将它们包含在using语句中)?

也是if检查是否cmd.Connection.State是的块ConnectionState.Open必需的,如果DI与提供的DbContext,该连接将已经打开?

顺便说一句,如果重要的话,我们正在使用AddDbContextPool注册DbContext来启用DbContext池。

Iva*_*oev 15

我的问题是,我在 DbContext 上使用GetDbConnection()CreateCommand(),所以我是否需要明确处理任何这些命令的结果(或将它们包含在 using 语句中)?

这些是不同的,后者的答案是肯定的,前者的答案是否定的。

您只需要遵循简单的原则 - 分配资源的代码负责清理它。

GetDbConnection(如单词 所示Get)不创建DbConnection对象,而是返回DbContext实例在其生命周期中创建和使用的对象。在这种情况下,DbContext拥有DbConnection,因此您不应处置该对象(这样做可能会破坏所有者功能)。

另一方面,CreateCommand 确实创建了新DbCommand对象,因此现在您的代码拥有它并负责在不再需要时处理它。

同样的原则适用于Open/ Close。同样,您的代码不拥有该DbConnection对象,因此您必须使其保持与检索它时相同的状态。EF Core 在处理需要打开连接的命令时在内部执行此操作 - 在开始时打开它,完成后关闭它。除非它是从外部打开的,在这种情况下他们什么都不做。这正是上述原则 - 如果您的代码这样做Open,那么它应该这样做Close,否则什么都不做。

所以有问题的代码应该是这样的(请注意,您的代码的关闭逻辑中存在一个错误 - 调用的条件Close应该是!isOpen,与Open调用相同):

public string GetId()
{
    using (var cmd = _context.Database.GetDbConnection().CreateCommand())
    {
        bool wasOpen = cmd.Connection.State == ConnectionState.Open;
        if (!wasOpen) cmd.Connection.Open();
        try
        {
            cmd.CommandText = "Select TOP 1 ID from ABC;";
            var result = (string)cmd.ExecuteScalar();
            return result;
        }
        finally
        {
            if (!wasOpen) cmd.Connection.Close();
        }
    }
} 
Run Code Online (Sandbox Code Playgroud)