Commit 07976041 authored by mgravell's avatar mgravell

fix #1277 - make sure that the command is disposed at the correct time when...

fix #1277 - make sure that the command is disposed at the correct time when using ExecuteReaderAsync; this means pushing it into WrappedReader, which was in turn overdue some love; as part of that, add netcoreapp2.1 target so we can expose the best reader possible
parent 191a1cb8
......@@ -5,7 +5,7 @@
<Title>Dapper (Strong Named)</Title>
<Description>A high performance Micro-ORM supporting SQL Server, MySQL, Sqlite, SqlCE, Firebird etc..</Description>
<Authors>Sam Saffron;Marc Gravell;Nick Craver</Authors>
<TargetFrameworks>net451;netstandard1.3;netstandard2.0</TargetFrameworks>
<TargetFrameworks>net451;netstandard1.3;netstandard2.0;netcoreapp2.1</TargetFrameworks>
<SignAssembly>true</SignAssembly>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
</PropertyGroup>
......@@ -24,6 +24,10 @@
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.4.0" />
<!-- it would be nice to use System.Data.Common here, but we need SqlClient for SqlDbType in 1.3, and legacy SqlDataRecord API-->
<!--<PackageReference Include="System.Data.Common" Version="4.3.0" />-->
<PackageReference Include="System.Data.SqlClient" Version="4.6.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp2.1'">
<PackageReference Include="System.Data.SqlClient" Version="4.6.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
......
......@@ -5,7 +5,7 @@
<Title>Dapper</Title>
<Description>A high performance Micro-ORM supporting SQL Server, MySQL, Sqlite, SqlCE, Firebird etc..</Description>
<Authors>Sam Saffron;Marc Gravell;Nick Craver</Authors>
<TargetFrameworks>net451;netstandard1.3;netstandard2.0</TargetFrameworks>
<TargetFrameworks>net451;netstandard1.3;netstandard2.0;netcoreapp2.1</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net451'">
<Reference Include="System" />
......@@ -19,6 +19,10 @@
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.4.0" />
<!-- it would be nice to use System.Data.Common here, but we need SqlClient for SqlDbType in 1.3, and legacy SqlDataRecord API-->
<!--<PackageReference Include="System.Data.Common" Version="4.3.0" />-->
<PackageReference Include="System.Data.SqlClient" Version="4.6.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp2.1'">
<PackageReference Include="System.Data.SqlClient" Version="4.6.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
......
......@@ -84,7 +84,11 @@ static class StructuredHelper
{
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, type);
#if NETSTANDARD1_3
il.Emit(OpCodes.Ldc_I4, (int)30); // hard-code the known enum value
#else
il.Emit(OpCodes.Ldc_I4, (int)SqlDbType.Structured);
#endif
il.EmitCall(OpCodes.Callvirt, dbType.GetSetMethod(), null);
}
......
......@@ -1101,7 +1101,7 @@ public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn,
/// </code>
/// </example>
public static Task<IDataReader> ExecuteReaderAsync(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null) =>
ExecuteReaderImplAsync(cnn, new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.Buffered), CommandBehavior.Default);
ExecuteWrappedReaderImplAsync(cnn, new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.Buffered), CommandBehavior.Default);
/// <summary>
/// Execute parameterized SQL and return an <see cref="IDataReader"/>.
......@@ -1114,7 +1114,7 @@ public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn,
/// or <see cref="T:DataSet"/>.
/// </remarks>
public static Task<IDataReader> ExecuteReaderAsync(this IDbConnection cnn, CommandDefinition command) =>
ExecuteReaderImplAsync(cnn, command, CommandBehavior.Default);
ExecuteWrappedReaderImplAsync(cnn, command, CommandBehavior.Default);
/// <summary>
/// Execute parameterized SQL and return an <see cref="IDataReader"/>.
......@@ -1128,26 +1128,27 @@ public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn,
/// or <see cref="T:DataSet"/>.
/// </remarks>
public static Task<IDataReader> ExecuteReaderAsync(this IDbConnection cnn, CommandDefinition command, CommandBehavior commandBehavior) =>
ExecuteReaderImplAsync(cnn, command, commandBehavior);
ExecuteWrappedReaderImplAsync(cnn, command, commandBehavior);
private static async Task<IDataReader> ExecuteReaderImplAsync(IDbConnection cnn, CommandDefinition command, CommandBehavior commandBehavior)
private static async Task<IDataReader> ExecuteWrappedReaderImplAsync(IDbConnection cnn, CommandDefinition command, CommandBehavior commandBehavior)
{
Action<IDbCommand, object> paramReader = GetParameterReader(cnn, ref command);
DbCommand cmd = null;
bool wasClosed = cnn.State == ConnectionState.Closed;
bool wasClosed = cnn.State == ConnectionState.Closed, disposeCommand = true;
try
{
cmd = command.TrySetupAsyncCommand(cnn, paramReader);
if (wasClosed) await cnn.TryOpenAsync(command.CancellationToken).ConfigureAwait(false);
var reader = await ExecuteReaderWithFlagsFallbackAsync(cmd, wasClosed, commandBehavior, command.CancellationToken).ConfigureAwait(false);
wasClosed = false;
return reader;
disposeCommand = false;
return WrappedReader.Create(cmd, reader);
}
finally
{
if (wasClosed) cnn.Close();
cmd?.Dispose();
if (cmd != null && disposeCommand) cmd.Dispose();
}
}
......
......@@ -599,7 +599,7 @@ public static IDataReader ExecuteReader(this IDbConnection cnn, string sql, obje
{
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.Buffered);
var reader = ExecuteReaderImpl(cnn, ref command, CommandBehavior.Default, out IDbCommand dbcmd);
return new WrappedReader(dbcmd, reader);
return WrappedReader.Create(dbcmd, reader);
}
/// <summary>
......@@ -615,7 +615,7 @@ public static IDataReader ExecuteReader(this IDbConnection cnn, string sql, obje
public static IDataReader ExecuteReader(this IDbConnection cnn, CommandDefinition command)
{
var reader = ExecuteReaderImpl(cnn, ref command, CommandBehavior.Default, out IDbCommand dbcmd);
return new WrappedReader(dbcmd, reader);
return WrappedReader.Create(dbcmd, reader);
}
/// <summary>
......@@ -632,7 +632,7 @@ public static IDataReader ExecuteReader(this IDbConnection cnn, CommandDefinitio
public static IDataReader ExecuteReader(this IDbConnection cnn, CommandDefinition command, CommandBehavior commandBehavior)
{
var reader = ExecuteReaderImpl(cnn, ref command, commandBehavior, out IDbCommand dbcmd);
return new WrappedReader(dbcmd, reader);
return WrappedReader.Create(dbcmd, reader);
}
/// <summary>
......@@ -3696,6 +3696,7 @@ public static void SetTypeName(this DataTable table, string typeName)
public static ICustomQueryParameter AsTableValuedParameter<T>(this IEnumerable<T> list, string typeName = null) where T : IDataRecord =>
new SqlDataRecordListTVPParameter<T>(list, typeName);
/*
/// <summary>
/// Used to pass a IEnumerable&lt;SqlDataRecord&gt; as a TableValuedParameter.
/// </summary>
......@@ -3704,6 +3705,7 @@ public static void SetTypeName(this DataTable table, string typeName)
public static ICustomQueryParameter AsTableValuedParameter(this IEnumerable<Microsoft.SqlServer.Server.SqlDataRecord> list, string typeName = null) =>
new SqlDataRecordListTVPParameter<Microsoft.SqlServer.Server.SqlDataRecord>(list, typeName);
// ^^^ retained to avoid missing-method-exception; can presumably drop in a "major"
*/
// one per thread
[ThreadStatic]
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment