Dapper 源代码 - 这会正确处理我的连接吗?

Dapper source code - will this dispose of my connection properly?

查看 Dappers QueryAsync 方法的源代码

SqlMapper.Async.cs

 private static async Task<IEnumerable<T>> QueryAsync<T>(this IDbConnection cnn, Type effectiveType, CommandDefinition command)
    {

        using (var cmd = command.TrySetupAsyncCommand(cnn, info.ParamReader))
        {
            DbDataReader reader = null;
            try
            {
                if (wasClosed) await cnn.TryOpenAsync(cancel).ConfigureAwait(false);

                var func = tuple.Func;

                if (command.Buffered)
                {
                    var buffer = new List<T>();
                    var convertToType = Nullable.GetUnderlyingType(effectiveType) ?? effectiveType;
                    while (await reader.ReadAsync(cancel).ConfigureAwait(false))
                    {
                        object val = func(reader);
                        if (val == null || val is T)
                        {
                            buffer.Add((T)val);
                        }
                        else
                        {
                            buffer.Add((T)Convert.ChangeType(val, convertToType, CultureInfo.InvariantCulture));
                        }
                    }
                    while (await reader.NextResultAsync(cancel).ConfigureAwait(false)) { /* ignore subsequent result sets */ }
                    command.OnCompleted();
                    return buffer;
                }
                else
                {
                    // can't use ReadAsync / cancellation; but this will have to do
                    wasClosed = false; // don't close if handing back an open reader; rely on the command-behavior
                    var deferred = ExecuteReaderSync<T>(reader, func, command.Parameters);
                    reader = null; // to prevent it being disposed before the caller gets to see it
                    return deferred;
                }
            }
            finally
            {
                using (reader) { /* dispose if non-null */ }
                if (wasClosed) cnn.Close();
            }
        }
    }

注意这一行 (413):

using (var cmd = command.TrySetupAsyncCommand(cnn, info.ParamReader))

我的问题是,我的连接是否会被正确处理,而无需将调用它的代码包装在 using 块中?

请注意您 post 代码中的以下行:

private static async Task<IEnumerable<T>> QueryAsync<T>(this IDbConnection cnn,....

说明QueryAsyncIDbConnection的扩展方法。这意味着,连接实例是在您的代码某处创建的。

如前所述,有两种方法可以管理与 Dapper 的连接:

  • 完全管理自己: 在这里,您全权负责打开和关闭连接。这就像您在使用 ADO.NET.

  • 时处理连接的方式一样
  • 允许Dapper管理它: Dapper 会自动为您打开连接(如果未打开)和关闭连接(如果它已被 Dapper 打开)。

考虑到这一点,这里唯一的选择是在您的代码中 open/close 连接或允许 Dapper 为您执行此操作。如果您自己这样做,那么 Dapper 根本不会干扰。

如果你想让Dapper为你处理open/close连接并且担心它是否会正确关闭它,那么是的,它会正确关闭它。

在您的 post 中找到以下代码:

if (wasClosed) await cnn.TryOpenAsync(cancel).ConfigureAwait(false);
....
if (wasClosed) cnn.Close();

如果 Dapper 打开连接,Dapper 会在 wasClosed 变量中维护 state/flag。您可以在代码中看到连接最后也正确关闭。此外,您可以进一步查看 Dapper 源代码以查看多个方法中的 this 是如何处理的。专门检查 SqlMapper.Async.csSqlMapper.cs 文件。

现在,这就是 open/close。 Dispose 呢?以下是 Marc Gravell 在 comment for this answer:

之一中所说的内容

well, technically open/closed is different to disposed. If you are only going to be opening/closing around the individual calls, you might as well let dapper do it. If you are opening/closing at a wider granularity (per request, for example), it would be better for your code to do it and pass an open connection to dapper.

因此,如果您真的想要 Dispose 连接而不只是 open/close,最好将其包装在代码中的 using 块中并将打开的连接传递给 Dapper。如评论中所述,this post 讨论了 DisposeClose 之间的区别。