mirror of
https://github.com/DapperLib/Dapper.git
synced 2026-10-16 21:03:18 +08:00
- add Meziantou.Analyzer to help check async usage scenarios
- fixup or suppress some noise from IDE and MA areas
This commit is contained in:
@@ -40,7 +40,7 @@ namespace Dapper.Contrib.Extensions
|
||||
if (!type.IsInterface)
|
||||
return (await connection.QueryAsync<T>(sql, dynParams, transaction, commandTimeout).ConfigureAwait(false)).FirstOrDefault();
|
||||
|
||||
if (!((await connection.QueryAsync<dynamic>(sql, dynParams).ConfigureAwait(false)).FirstOrDefault() is IDictionary<string, object> res))
|
||||
if ((await connection.QueryAsync<dynamic>(sql, dynParams).ConfigureAwait(false)).FirstOrDefault() is not IDictionary<string, object> res)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ namespace Dapper.Contrib.Extensions
|
||||
|
||||
if (type.IsInterface)
|
||||
{
|
||||
if (!(connection.Query(sql, dynParams).FirstOrDefault() is IDictionary<string, object> res))
|
||||
if (connection.Query(sql, dynParams).FirstOrDefault() is not IDictionary<string, object> res)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<Description>A high performance Micro-ORM supporting SQL Server, MySQL, Sqlite, SqlCE, Firebird etc..</Description>
|
||||
<Authors>Sam Saffron;Marc Gravell;Nick Craver</Authors>
|
||||
<TargetFrameworks>net461;netstandard2.0;net5.0</TargetFrameworks>
|
||||
<NoWarn>$(NoWarn);MA0006;MA0007;MA0009;MA0003;MA0023;MA0051;MA0071;MA0048;MA0018;MA0012</NoWarn>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
@@ -17,5 +18,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0'">
|
||||
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" />
|
||||
|
||||
<PackageReference Include="Meziantou.Analyzer" Version="1.0.638" PrivateAssets="All" IncludeAssets="runtime; build; native; contentfiles; analyzers" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Dapper
|
||||
{
|
||||
public object Parse(Type destinationType, object value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public void SetValue(IDbDataParameter parameter, object value)
|
||||
|
||||
@@ -177,6 +177,8 @@ namespace Dapper
|
||||
/// <summary>
|
||||
/// The settable properties for this typemap
|
||||
/// </summary>
|
||||
#pragma warning disable MA0016 // Prefer return collection abstraction instead of implementation
|
||||
public List<PropertyInfo> Properties { get; }
|
||||
#pragma warning restore MA0016 // Prefer return collection abstraction instead of implementation
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Dapper
|
||||
{
|
||||
internal const DbType EnumerableMultiParameter = (DbType)(-1);
|
||||
private static readonly Dictionary<SqlMapper.Identity, Action<IDbCommand, object>> paramReaderCache = new Dictionary<SqlMapper.Identity, Action<IDbCommand, object>>();
|
||||
private readonly Dictionary<string, ParamInfo> parameters = new Dictionary<string, ParamInfo>();
|
||||
private readonly Dictionary<string, ParamInfo> parameters = new Dictionary<string, ParamInfo>(StringComparer.Ordinal);
|
||||
private List<object> templates;
|
||||
|
||||
object SqlMapper.IParameterLookup.this[string name] =>
|
||||
@@ -162,7 +162,7 @@ namespace Dapper
|
||||
/// <param name="identity">Information about the query</param>
|
||||
protected void AddParameters(IDbCommand command, SqlMapper.Identity identity)
|
||||
{
|
||||
var literals = SqlMapper.GetLiteralTokens(identity.sql);
|
||||
var literals = SqlMapper.GetLiteralTokens(identity._sql);
|
||||
|
||||
if (templates != null)
|
||||
{
|
||||
@@ -316,7 +316,7 @@ namespace Dapper
|
||||
{
|
||||
if (default(T) != null)
|
||||
{
|
||||
throw new ApplicationException("Attempting to cast a DBNull to a non nullable type! Note that out/return parameters will not have updated values until the data stream completes (after the 'foreach' for Query(..., buffered: false), or after the GridReader has been disposed for QueryMultiple)");
|
||||
throw new InvalidOperationException("Attempting to cast a DBNull to a non nullable type! Note that out/return parameters will not have updated values until the data stream completes (after the 'foreach' for Query(..., buffered: false), or after the GridReader has been disposed for QueryMultiple)");
|
||||
}
|
||||
return default;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,11 @@ namespace Dapper
|
||||
if (task is null) throw new ArgumentNullException(nameof(task));
|
||||
|
||||
if (task.Status == TaskStatus.RanToCompletion)
|
||||
{
|
||||
#pragma warning disable MA0042 // use await instead of Result; nope, we've already checked
|
||||
return Task.FromResult((TTo)task.Result);
|
||||
#pragma warning restore MA0042
|
||||
}
|
||||
|
||||
var source = new TaskCompletionSource<TTo>();
|
||||
task.ContinueWith(OnTaskCompleted<TFrom, TTo>, state: source, TaskContinuationOptions.ExecuteSynchronously);
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Dapper
|
||||
/// <summary>
|
||||
/// Handles variances in features per DBMS
|
||||
/// </summary>
|
||||
internal class FeatureSupport
|
||||
internal sealed class FeatureSupport
|
||||
{
|
||||
private static readonly FeatureSupport
|
||||
Default = new FeatureSupport(false),
|
||||
|
||||
@@ -946,7 +946,9 @@ namespace Dapper
|
||||
{
|
||||
if (types.Length < 1)
|
||||
{
|
||||
#pragma warning disable MA0015 // missing name
|
||||
throw new ArgumentException("you must provide at least one type to deserialize");
|
||||
#pragma warning restore MA0015 // missing name
|
||||
}
|
||||
|
||||
object param = command.Parameters;
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Dapper
|
||||
{
|
||||
public static partial class SqlMapper
|
||||
{
|
||||
private class CacheInfo
|
||||
private sealed class CacheInfo
|
||||
{
|
||||
public DeserializerState Deserializer { get; set; }
|
||||
public Func<IDataReader, object>[] OtherDeserializers { get; set; }
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
/// <summary>
|
||||
/// Dummy type for excluding from multi-map
|
||||
/// </summary>
|
||||
private class DontMap { /* hiding constructor */ }
|
||||
private sealed class DontMap { /* hiding constructor */ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ namespace Dapper
|
||||
|
||||
private async Task NextResultAsync()
|
||||
{
|
||||
if (await ((DbDataReader)reader).NextResultAsync(cancel).ConfigureAwait(false))
|
||||
if (await ((DbDataReader)_reader).NextResultAsync(cancel).ConfigureAwait(false))
|
||||
{
|
||||
// readCount++;
|
||||
gridIndex++;
|
||||
@@ -149,29 +149,29 @@ namespace Dapper
|
||||
{
|
||||
// happy path; close the reader cleanly - no
|
||||
// need for "Cancel" etc
|
||||
reader.Dispose();
|
||||
reader = null;
|
||||
callbacks?.OnCompleted();
|
||||
_reader.Dispose();
|
||||
_reader = null;
|
||||
_callbacks?.OnCompleted();
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private Task<IEnumerable<T>> ReadAsyncImpl<T>(Type type, bool buffered)
|
||||
{
|
||||
if (reader == null) throw new ObjectDisposedException(GetType().FullName, "The reader has been disposed; this can happen after all data has been consumed");
|
||||
if (_reader == null) throw new ObjectDisposedException(GetType().FullName, "The reader has been disposed; this can happen after all data has been consumed");
|
||||
if (IsConsumed) throw new InvalidOperationException("Query results must be consumed in the correct order, and each result can only be consumed once");
|
||||
var typedIdentity = identity.ForGrid(type, gridIndex);
|
||||
CacheInfo cache = GetCacheInfo(typedIdentity, null, addToCache);
|
||||
var typedIdentity = _identity.ForGrid(type, gridIndex);
|
||||
CacheInfo cache = GetCacheInfo(typedIdentity, null, _addToCache);
|
||||
var deserializer = cache.Deserializer;
|
||||
|
||||
int hash = GetColumnHash(reader);
|
||||
int hash = GetColumnHash(_reader);
|
||||
if (deserializer.Func == null || deserializer.Hash != hash)
|
||||
{
|
||||
deserializer = new DeserializerState(hash, GetDeserializer(type, reader, 0, -1, false));
|
||||
deserializer = new DeserializerState(hash, GetDeserializer(type, _reader, 0, -1, false));
|
||||
cache.Deserializer = deserializer;
|
||||
}
|
||||
IsConsumed = true;
|
||||
if (buffered && reader is DbDataReader)
|
||||
if (buffered && _reader is DbDataReader)
|
||||
{
|
||||
return ReadBufferedAsync<T>(gridIndex, deserializer.Func);
|
||||
}
|
||||
@@ -185,7 +185,7 @@ namespace Dapper
|
||||
|
||||
private Task<T> ReadRowAsyncImpl<T>(Type type, Row row)
|
||||
{
|
||||
if (reader is DbDataReader dbReader) return ReadRowAsyncImplViaDbReader<T>(dbReader, type, row);
|
||||
if (_reader is DbDataReader dbReader) return ReadRowAsyncImplViaDbReader<T>(dbReader, type, row);
|
||||
|
||||
// no async API available; use non-async and fake it
|
||||
return Task.FromResult(ReadRow<T>(type, row));
|
||||
@@ -200,8 +200,8 @@ namespace Dapper
|
||||
T result = default;
|
||||
if (await reader.ReadAsync(cancel).ConfigureAwait(false) && reader.FieldCount != 0)
|
||||
{
|
||||
var typedIdentity = identity.ForGrid(type, gridIndex);
|
||||
CacheInfo cache = GetCacheInfo(typedIdentity, null, addToCache);
|
||||
var typedIdentity = _identity.ForGrid(type, gridIndex);
|
||||
CacheInfo cache = GetCacheInfo(typedIdentity, null, _addToCache);
|
||||
var deserializer = cache.Deserializer;
|
||||
|
||||
int hash = GetColumnHash(reader);
|
||||
@@ -226,7 +226,7 @@ namespace Dapper
|
||||
{
|
||||
try
|
||||
{
|
||||
var reader = (DbDataReader)this.reader;
|
||||
var reader = (DbDataReader)_reader;
|
||||
var buffer = new List<T>();
|
||||
while (index == gridIndex && await reader.ReadAsync(cancel).ConfigureAwait(false))
|
||||
{
|
||||
|
||||
@@ -12,17 +12,17 @@ namespace Dapper
|
||||
/// </summary>
|
||||
public partial class GridReader : IDisposable
|
||||
{
|
||||
private IDataReader reader;
|
||||
private readonly Identity identity;
|
||||
private readonly bool addToCache;
|
||||
private IDataReader _reader;
|
||||
private readonly Identity _identity;
|
||||
private readonly bool _addToCache;
|
||||
|
||||
internal GridReader(IDbCommand command, IDataReader reader, Identity identity, IParameterCallbacks callbacks, bool addToCache)
|
||||
{
|
||||
Command = command;
|
||||
this.reader = reader;
|
||||
this.identity = identity;
|
||||
this.callbacks = callbacks;
|
||||
this.addToCache = addToCache;
|
||||
_reader = reader;
|
||||
_identity = identity;
|
||||
_callbacks = callbacks;
|
||||
_addToCache = addToCache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -145,16 +145,16 @@ namespace Dapper
|
||||
|
||||
private IEnumerable<T> ReadImpl<T>(Type type, bool buffered)
|
||||
{
|
||||
if (reader == null) throw new ObjectDisposedException(GetType().FullName, "The reader has been disposed; this can happen after all data has been consumed");
|
||||
if (_reader == null) throw new ObjectDisposedException(GetType().FullName, "The reader has been disposed; this can happen after all data has been consumed");
|
||||
if (IsConsumed) throw new InvalidOperationException("Query results must be consumed in the correct order, and each result can only be consumed once");
|
||||
var typedIdentity = identity.ForGrid(type, gridIndex);
|
||||
CacheInfo cache = GetCacheInfo(typedIdentity, null, addToCache);
|
||||
var typedIdentity = _identity.ForGrid(type, gridIndex);
|
||||
CacheInfo cache = GetCacheInfo(typedIdentity, null, _addToCache);
|
||||
var deserializer = cache.Deserializer;
|
||||
|
||||
int hash = GetColumnHash(reader);
|
||||
int hash = GetColumnHash(_reader);
|
||||
if (deserializer.Func == null || deserializer.Hash != hash)
|
||||
{
|
||||
deserializer = new DeserializerState(hash, GetDeserializer(type, reader, 0, -1, false));
|
||||
deserializer = new DeserializerState(hash, GetDeserializer(type, _reader, 0, -1, false));
|
||||
cache.Deserializer = deserializer;
|
||||
}
|
||||
IsConsumed = true;
|
||||
@@ -164,24 +164,24 @@ namespace Dapper
|
||||
|
||||
private T ReadRow<T>(Type type, Row row)
|
||||
{
|
||||
if (reader == null) throw new ObjectDisposedException(GetType().FullName, "The reader has been disposed; this can happen after all data has been consumed");
|
||||
if (_reader == null) throw new ObjectDisposedException(GetType().FullName, "The reader has been disposed; this can happen after all data has been consumed");
|
||||
if (IsConsumed) throw new InvalidOperationException("Query results must be consumed in the correct order, and each result can only be consumed once");
|
||||
IsConsumed = true;
|
||||
|
||||
T result = default;
|
||||
if (reader.Read() && reader.FieldCount != 0)
|
||||
if (_reader.Read() && _reader.FieldCount != 0)
|
||||
{
|
||||
var typedIdentity = identity.ForGrid(type, gridIndex);
|
||||
CacheInfo cache = GetCacheInfo(typedIdentity, null, addToCache);
|
||||
var typedIdentity = _identity.ForGrid(type, gridIndex);
|
||||
CacheInfo cache = GetCacheInfo(typedIdentity, null, _addToCache);
|
||||
var deserializer = cache.Deserializer;
|
||||
|
||||
int hash = GetColumnHash(reader);
|
||||
int hash = GetColumnHash(_reader);
|
||||
if (deserializer.Func == null || deserializer.Hash != hash)
|
||||
{
|
||||
deserializer = new DeserializerState(hash, GetDeserializer(type, reader, 0, -1, false));
|
||||
deserializer = new DeserializerState(hash, GetDeserializer(type, _reader, 0, -1, false));
|
||||
cache.Deserializer = deserializer;
|
||||
}
|
||||
object val = deserializer.Func(reader);
|
||||
object val = deserializer.Func(_reader);
|
||||
if (val == null || val is T)
|
||||
{
|
||||
result = (T)val;
|
||||
@@ -191,8 +191,8 @@ namespace Dapper
|
||||
var convertToType = Nullable.GetUnderlyingType(type) ?? type;
|
||||
result = (T)Convert.ChangeType(val, convertToType, CultureInfo.InvariantCulture);
|
||||
}
|
||||
if ((row & Row.Single) != 0 && reader.Read()) ThrowMultipleRows(row);
|
||||
while (reader.Read()) { /* ignore subsequent rows */ }
|
||||
if ((row & Row.Single) != 0 && _reader.Read()) ThrowMultipleRows(row);
|
||||
while (_reader.Read()) { /* ignore subsequent rows */ }
|
||||
}
|
||||
else if ((row & Row.FirstOrDefault) == 0) // demanding a row, and don't have one
|
||||
{
|
||||
@@ -204,13 +204,13 @@ namespace Dapper
|
||||
|
||||
private IEnumerable<TReturn> MultiReadInternal<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(Delegate func, string splitOn)
|
||||
{
|
||||
var identity = this.identity.ForGrid<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh>(typeof(TReturn), gridIndex);
|
||||
var identity = _identity.ForGrid<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh>(typeof(TReturn), gridIndex);
|
||||
|
||||
IsConsumed = true;
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var r in MultiMapImpl<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(null, default, func, splitOn, reader, identity, false))
|
||||
foreach (var r in MultiMapImpl<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(null, default, func, splitOn, _reader, identity, false))
|
||||
{
|
||||
yield return r;
|
||||
}
|
||||
@@ -223,10 +223,10 @@ namespace Dapper
|
||||
|
||||
private IEnumerable<TReturn> MultiReadInternal<TReturn>(Type[] types, Func<object[], TReturn> map, string splitOn)
|
||||
{
|
||||
var identity = this.identity.ForGrid(typeof(TReturn), types, gridIndex);
|
||||
var identity = _identity.ForGrid(typeof(TReturn), types, gridIndex);
|
||||
try
|
||||
{
|
||||
foreach (var r in MultiMapImpl<TReturn>(null, default, types, map, splitOn, reader, identity, false))
|
||||
foreach (var r in MultiMapImpl<TReturn>(null, default, types, map, splitOn, _reader, identity, false))
|
||||
{
|
||||
yield return r;
|
||||
}
|
||||
@@ -361,9 +361,9 @@ namespace Dapper
|
||||
try
|
||||
{
|
||||
var convertToType = Nullable.GetUnderlyingType(effectiveType) ?? effectiveType;
|
||||
while (index == gridIndex && reader.Read())
|
||||
while (index == gridIndex && _reader.Read())
|
||||
{
|
||||
object val = deserializer(reader);
|
||||
object val = deserializer(_reader);
|
||||
if (val == null || val is T)
|
||||
{
|
||||
yield return (T)val;
|
||||
@@ -384,7 +384,7 @@ namespace Dapper
|
||||
}
|
||||
|
||||
private int gridIndex; //, readCount;
|
||||
private readonly IParameterCallbacks callbacks;
|
||||
private readonly IParameterCallbacks _callbacks;
|
||||
|
||||
/// <summary>
|
||||
/// Has the underlying reader been consumed?
|
||||
@@ -398,7 +398,7 @@ namespace Dapper
|
||||
|
||||
private void NextResult()
|
||||
{
|
||||
if (reader.NextResult())
|
||||
if (_reader.NextResult())
|
||||
{
|
||||
// readCount++;
|
||||
gridIndex++;
|
||||
@@ -408,9 +408,9 @@ namespace Dapper
|
||||
{
|
||||
// happy path; close the reader cleanly - no
|
||||
// need for "Cancel" etc
|
||||
reader.Dispose();
|
||||
reader = null;
|
||||
callbacks?.OnCompleted();
|
||||
_reader.Dispose();
|
||||
_reader = null;
|
||||
_callbacks?.OnCompleted();
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
@@ -420,11 +420,11 @@ namespace Dapper
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (reader != null)
|
||||
if (_reader != null)
|
||||
{
|
||||
if (!reader.IsClosed) Command?.Cancel();
|
||||
reader.Dispose();
|
||||
reader = null;
|
||||
if (!_reader.IsClosed) Command?.Cancel();
|
||||
_reader.Dispose();
|
||||
_reader = null;
|
||||
}
|
||||
if (Command != null)
|
||||
{
|
||||
|
||||
@@ -93,15 +93,15 @@ namespace Dapper
|
||||
internal virtual Type GetType(int index) => throw new IndexOutOfRangeException(nameof(index));
|
||||
|
||||
internal Identity ForGrid<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh>(Type primaryType, int gridIndex) =>
|
||||
new Identity<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh>(sql, commandType, connectionString, primaryType, parametersType, gridIndex);
|
||||
new Identity<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh>(_sql, _commandType, _connectionString, primaryType, _parametersType, gridIndex);
|
||||
|
||||
internal Identity ForGrid(Type primaryType, int gridIndex) =>
|
||||
new Identity(sql, commandType, connectionString, primaryType, parametersType, 0, gridIndex);
|
||||
new Identity(_sql, _commandType, _connectionString, primaryType, _parametersType, 0, gridIndex);
|
||||
|
||||
internal Identity ForGrid(Type primaryType, Type[] otherTypes, int gridIndex) =>
|
||||
(otherTypes == null || otherTypes.Length == 0)
|
||||
? new Identity(sql, commandType, connectionString, primaryType, parametersType, 0, gridIndex)
|
||||
: new IdentityWithTypes(sql, commandType, connectionString, primaryType, parametersType, otherTypes, gridIndex);
|
||||
? new Identity(_sql, _commandType, _connectionString, primaryType, _parametersType, 0, gridIndex)
|
||||
: new IdentityWithTypes(_sql, _commandType, _connectionString, primaryType, _parametersType, otherTypes, gridIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Create an identity for use with DynamicParameters, internal use only.
|
||||
@@ -109,29 +109,31 @@ namespace Dapper
|
||||
/// <param name="type">The parameters type to create an <see cref="Identity"/> for.</param>
|
||||
/// <returns></returns>
|
||||
public Identity ForDynamicParameters(Type type) =>
|
||||
new Identity(sql, commandType, connectionString, this.type, type, 0, -1);
|
||||
new Identity(_sql, _commandType, _connectionString, _type, type, 0, -1);
|
||||
|
||||
internal Identity(string sql, CommandType? commandType, IDbConnection connection, Type type, Type parametersType)
|
||||
: this(sql, commandType, connection.ConnectionString, type, parametersType, 0, 0) { /* base call */ }
|
||||
|
||||
private protected Identity(string sql, CommandType? commandType, string connectionString, Type type, Type parametersType, int otherTypesHash, int gridIndex)
|
||||
{
|
||||
this.sql = sql;
|
||||
this.commandType = commandType;
|
||||
this.connectionString = connectionString;
|
||||
this.type = type;
|
||||
this.parametersType = parametersType;
|
||||
this.gridIndex = gridIndex;
|
||||
_sql = sql;
|
||||
_commandType = commandType;
|
||||
_connectionString = connectionString;
|
||||
_type = type;
|
||||
_parametersType = parametersType;
|
||||
_gridIndex = gridIndex;
|
||||
unchecked
|
||||
{
|
||||
hashCode = 17; // we *know* we are using this in a dictionary, so pre-compute this
|
||||
hashCode = (hashCode * 23) + commandType.GetHashCode();
|
||||
hashCode = (hashCode * 23) + gridIndex.GetHashCode();
|
||||
hashCode = (hashCode * 23) + (sql?.GetHashCode() ?? 0);
|
||||
hashCode = (hashCode * 23) + (type?.GetHashCode() ?? 0);
|
||||
hashCode = (hashCode * 23) + otherTypesHash;
|
||||
hashCode = (hashCode * 23) + (connectionString == null ? 0 : connectionStringComparer.GetHashCode(connectionString));
|
||||
hashCode = (hashCode * 23) + (parametersType?.GetHashCode() ?? 0);
|
||||
_hashCode = 17; // we *know* we are using this in a dictionary, so pre-compute this
|
||||
_hashCode = (_hashCode * 23) + commandType.GetHashCode();
|
||||
_hashCode = (_hashCode * 23) + gridIndex.GetHashCode();
|
||||
#pragma warning disable MA0021 // use specific StringComparer to compute hash codes
|
||||
_hashCode = (_hashCode * 23) + (sql?.GetHashCode() ?? 0);
|
||||
#pragma warning restore MA0021
|
||||
_hashCode = (_hashCode * 23) + (type?.GetHashCode() ?? 0);
|
||||
_hashCode = (_hashCode * 23) + otherTypesHash;
|
||||
_hashCode = (_hashCode * 23) + (connectionString == null ? 0 : connectionStringComparer.GetHashCode(connectionString));
|
||||
_hashCode = (_hashCode * 23) + (parametersType?.GetHashCode() ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,48 +146,48 @@ namespace Dapper
|
||||
/// <summary>
|
||||
/// The raw SQL command.
|
||||
/// </summary>
|
||||
public readonly string sql;
|
||||
public readonly string _sql;
|
||||
|
||||
/// <summary>
|
||||
/// The SQL command type.
|
||||
/// </summary>
|
||||
public readonly CommandType? commandType;
|
||||
public readonly CommandType? _commandType;
|
||||
|
||||
/// <summary>
|
||||
/// The hash code of this Identity.
|
||||
/// </summary>
|
||||
public readonly int hashCode;
|
||||
public readonly int _hashCode;
|
||||
|
||||
/// <summary>
|
||||
/// The grid index (position in the reader) of this Identity.
|
||||
/// </summary>
|
||||
public readonly int gridIndex;
|
||||
public readonly int _gridIndex;
|
||||
|
||||
/// <summary>
|
||||
/// This <see cref="Type"/> of this Identity.
|
||||
/// </summary>
|
||||
public readonly Type type;
|
||||
public readonly Type _type;
|
||||
|
||||
/// <summary>
|
||||
/// The connection string for this Identity.
|
||||
/// </summary>
|
||||
public readonly string connectionString;
|
||||
public readonly string _connectionString;
|
||||
|
||||
/// <summary>
|
||||
/// The type of the parameters object for this Identity.
|
||||
/// </summary>
|
||||
public readonly Type parametersType;
|
||||
public readonly Type _parametersType;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hash code for this identity.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override int GetHashCode() => hashCode;
|
||||
public override int GetHashCode() => _hashCode;
|
||||
|
||||
/// <summary>
|
||||
/// See object.ToString()
|
||||
/// </summary>
|
||||
public override string ToString() => sql;
|
||||
public override string ToString() => _sql;
|
||||
|
||||
/// <summary>
|
||||
/// Compare 2 Identity objects
|
||||
@@ -198,12 +200,12 @@ namespace Dapper
|
||||
if (other is null) return false;
|
||||
|
||||
int typeCount;
|
||||
return gridIndex == other.gridIndex
|
||||
&& type == other.type
|
||||
&& sql == other.sql
|
||||
&& commandType == other.commandType
|
||||
&& connectionStringComparer.Equals(connectionString, other.connectionString)
|
||||
&& parametersType == other.parametersType
|
||||
return _gridIndex == other._gridIndex
|
||||
&& _type == other._type
|
||||
&& _sql == other._sql
|
||||
&& _commandType == other._commandType
|
||||
&& connectionStringComparer.Equals(_connectionString, other._connectionString)
|
||||
&& _parametersType == other._parametersType
|
||||
&& (typeCount = TypeCount) == other.TypeCount
|
||||
&& (typeCount == 0 || TypesEqual(this, other, typeCount));
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Dapper
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">The type to cache.</typeparam>
|
||||
/// <typeparam name="TValue">The value type of the cache.</typeparam>
|
||||
internal class Link<TKey, TValue> where TKey : class
|
||||
internal sealed class Link<TKey, TValue> where TKey : class
|
||||
{
|
||||
public static bool TryGet(Link<TKey, TValue> link, TKey key, out TValue value)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Dapper
|
||||
{
|
||||
public static partial class SqlMapper
|
||||
{
|
||||
private class TypeDeserializerCache
|
||||
private sealed class TypeDeserializerCache
|
||||
{
|
||||
private TypeDeserializerCache(Type type)
|
||||
{
|
||||
|
||||
+87
-74
@@ -27,7 +27,7 @@ namespace Dapper
|
||||
/// </summary>
|
||||
public static partial class SqlMapper
|
||||
{
|
||||
private class PropertyInfoByNameComparer : IComparer<PropertyInfo>
|
||||
private sealed class PropertyInfoByNameComparer : IComparer<PropertyInfo>
|
||||
{
|
||||
public int Compare(PropertyInfo x, PropertyInfo y) => string.CompareOrdinal(x.Name, y.Name);
|
||||
}
|
||||
@@ -112,7 +112,7 @@ namespace Dapper
|
||||
{
|
||||
foreach (var entry in _queryCache)
|
||||
{
|
||||
if (entry.Key.type == type)
|
||||
if (entry.Key._type == type)
|
||||
_queryCache.TryRemove(entry.Key, out CacheInfo _);
|
||||
}
|
||||
TypeDeserializerCache.Purge(type);
|
||||
@@ -134,7 +134,7 @@ namespace Dapper
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Tuple<string, string, int>> GetCachedSQL(int ignoreHitCountAbove = int.MaxValue)
|
||||
{
|
||||
var data = _queryCache.Select(pair => Tuple.Create(pair.Key.connectionString, pair.Key.sql, pair.Value.GetHitCount()));
|
||||
var data = _queryCache.Select(pair => Tuple.Create(pair.Key._connectionString, pair.Key._sql, pair.Value.GetHitCount()));
|
||||
return (ignoreHitCountAbove < int.MaxValue)
|
||||
? data.Where(tuple => tuple.Item3 <= ignoreHitCountAbove)
|
||||
: data;
|
||||
@@ -149,13 +149,13 @@ namespace Dapper
|
||||
var counts = new Dictionary<int, int>();
|
||||
foreach (var key in _queryCache.Keys)
|
||||
{
|
||||
if (!counts.TryGetValue(key.hashCode, out int count))
|
||||
if (!counts.TryGetValue(key._hashCode, out int count))
|
||||
{
|
||||
counts.Add(key.hashCode, 1);
|
||||
counts.Add(key._hashCode, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
counts[key.hashCode] = count + 1;
|
||||
counts[key._hashCode] = count + 1;
|
||||
}
|
||||
}
|
||||
return from pair in counts
|
||||
@@ -163,11 +163,11 @@ namespace Dapper
|
||||
select Tuple.Create(pair.Key, pair.Value);
|
||||
}
|
||||
|
||||
private static Dictionary<Type, DbType> typeMap;
|
||||
private static Dictionary<Type, DbType> s_typeMap;
|
||||
|
||||
static SqlMapper()
|
||||
{
|
||||
typeMap = new Dictionary<Type, DbType>(37)
|
||||
s_typeMap = new Dictionary<Type, DbType>(37)
|
||||
{
|
||||
[typeof(byte)] = DbType.Byte,
|
||||
[typeof(sbyte)] = DbType.SByte,
|
||||
@@ -232,11 +232,11 @@ namespace Dapper
|
||||
public static void AddTypeMap(Type type, DbType dbType)
|
||||
{
|
||||
// use clone, mutate, replace to avoid threading issues
|
||||
var snapshot = typeMap;
|
||||
var snapshot = s_typeMap;
|
||||
|
||||
if (snapshot.TryGetValue(type, out DbType oldValue) && oldValue == dbType) return; // nothing to do
|
||||
|
||||
typeMap = new Dictionary<Type, DbType>(snapshot) { [type] = dbType };
|
||||
s_typeMap = new Dictionary<Type, DbType>(snapshot) { [type] = dbType };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -246,14 +246,14 @@ namespace Dapper
|
||||
public static void RemoveTypeMap(Type type)
|
||||
{
|
||||
// use clone, mutate, replace to avoid threading issues
|
||||
var snapshot = typeMap;
|
||||
var snapshot = s_typeMap;
|
||||
|
||||
if (!snapshot.ContainsKey(type)) return; // nothing to do
|
||||
|
||||
var newCopy = new Dictionary<Type, DbType>(snapshot);
|
||||
newCopy.Remove(type);
|
||||
|
||||
typeMap = newCopy;
|
||||
s_typeMap = newCopy;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -358,11 +358,11 @@ namespace Dapper
|
||||
handler = null;
|
||||
var nullUnderlyingType = Nullable.GetUnderlyingType(type);
|
||||
if (nullUnderlyingType != null) type = nullUnderlyingType;
|
||||
if (type.IsEnum && !typeMap.ContainsKey(type))
|
||||
if (type.IsEnum && !s_typeMap.ContainsKey(type))
|
||||
{
|
||||
type = Enum.GetUnderlyingType(type);
|
||||
}
|
||||
if (typeMap.TryGetValue(type, out DbType dbType))
|
||||
if (s_typeMap.TryGetValue(type, out DbType dbType))
|
||||
{
|
||||
return dbType;
|
||||
}
|
||||
@@ -424,7 +424,9 @@ namespace Dapper
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of element in the list.</typeparam>
|
||||
/// <param name="source">The enumerable to return as a list.</param>
|
||||
#pragma warning disable MA0016 // Prefer return collection abstraction instead of implementation
|
||||
public static List<T> AsList<T>(this IEnumerable<T> source) =>
|
||||
#pragma warning restore MA0016 // Prefer return collection abstraction instead of implementation
|
||||
(source == null || source is List<T>) ? (List<T>)source : source.ToList();
|
||||
|
||||
/// <summary>
|
||||
@@ -1150,7 +1152,9 @@ namespace Dapper
|
||||
{
|
||||
_ = row switch
|
||||
{ // get the standard exception from the runtime
|
||||
#pragma warning disable MA0098 // use [0] instead of First; nope: I want the error type/message!
|
||||
Row.First => ErrZeroRows.First(),
|
||||
#pragma warning restore MA0098 // use [0] instead of First
|
||||
Row.Single => ErrZeroRows.Single(),
|
||||
_ => throw new InvalidOperationException(),
|
||||
};
|
||||
@@ -1498,63 +1502,70 @@ namespace Dapper
|
||||
{
|
||||
if (types.Length < 1)
|
||||
{
|
||||
#pragma warning disable MA0015 // missing name
|
||||
throw new ArgumentException("you must provide at least one type to deserialize");
|
||||
#pragma warning restore MA0015 // missing name
|
||||
}
|
||||
|
||||
object param = command.Parameters;
|
||||
identity ??= new IdentityWithTypes(command.CommandText, command.CommandType, cnn, types[0], param?.GetType(), types);
|
||||
CacheInfo cinfo = GetCacheInfo(identity, param, command.AddToCache);
|
||||
|
||||
IDbCommand ownedCommand = null;
|
||||
IDataReader ownedReader = null;
|
||||
return Impl(cnn, command, types, map, splitOn, reader, identity, finalize, cinfo);
|
||||
|
||||
bool wasClosed = cnn?.State == ConnectionState.Closed;
|
||||
try
|
||||
static IEnumerable<TReturn> Impl(IDbConnection cnn, CommandDefinition command, Type[] types, Func<object[], TReturn> map, string splitOn, IDataReader reader, Identity identity, bool finalize, CacheInfo cinfo)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
ownedCommand = command.SetupCommand(cnn, cinfo.ParamReader);
|
||||
if (wasClosed) cnn.Open();
|
||||
ownedReader = ExecuteReaderWithFlagsFallback(ownedCommand, wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult);
|
||||
reader = ownedReader;
|
||||
}
|
||||
DeserializerState deserializer;
|
||||
Func<IDataReader, object>[] otherDeserializers;
|
||||
IDbCommand ownedCommand = null;
|
||||
IDataReader ownedReader = null;
|
||||
|
||||
int hash = GetColumnHash(reader);
|
||||
if ((deserializer = cinfo.Deserializer).Func == null || (otherDeserializers = cinfo.OtherDeserializers) == null || hash != deserializer.Hash)
|
||||
{
|
||||
var deserializers = GenerateDeserializers(identity, splitOn, reader);
|
||||
deserializer = cinfo.Deserializer = new DeserializerState(hash, deserializers[0]);
|
||||
otherDeserializers = cinfo.OtherDeserializers = deserializers.Skip(1).ToArray();
|
||||
SetQueryCache(identity, cinfo);
|
||||
}
|
||||
|
||||
Func<IDataReader, TReturn> mapIt = GenerateMapper(types.Length, deserializer.Func, otherDeserializers, map);
|
||||
|
||||
if (mapIt != null)
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
yield return mapIt(reader);
|
||||
}
|
||||
if (finalize)
|
||||
{
|
||||
while (reader.NextResult()) { /* ignore subsequent result sets */ }
|
||||
command.OnCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
bool wasClosed = cnn?.State == ConnectionState.Closed;
|
||||
try
|
||||
{
|
||||
ownedReader?.Dispose();
|
||||
if (reader == null)
|
||||
{
|
||||
ownedCommand = command.SetupCommand(cnn, cinfo.ParamReader);
|
||||
if (wasClosed) cnn.Open();
|
||||
ownedReader = ExecuteReaderWithFlagsFallback(ownedCommand, wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult);
|
||||
reader = ownedReader;
|
||||
}
|
||||
DeserializerState deserializer;
|
||||
Func<IDataReader, object>[] otherDeserializers;
|
||||
|
||||
int hash = GetColumnHash(reader);
|
||||
if ((deserializer = cinfo.Deserializer).Func == null || (otherDeserializers = cinfo.OtherDeserializers) == null || hash != deserializer.Hash)
|
||||
{
|
||||
var deserializers = GenerateDeserializers(identity, splitOn, reader);
|
||||
deserializer = cinfo.Deserializer = new DeserializerState(hash, deserializers[0]);
|
||||
otherDeserializers = cinfo.OtherDeserializers = deserializers.Skip(1).ToArray();
|
||||
SetQueryCache(identity, cinfo);
|
||||
}
|
||||
|
||||
Func<IDataReader, TReturn> mapIt = GenerateMapper(types.Length, deserializer.Func, otherDeserializers, map);
|
||||
|
||||
if (mapIt != null)
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
yield return mapIt(reader);
|
||||
}
|
||||
if (finalize)
|
||||
{
|
||||
while (reader.NextResult()) { /* ignore subsequent result sets */ }
|
||||
command.OnCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ownedCommand?.Dispose();
|
||||
if (wasClosed) cnn.Close();
|
||||
try
|
||||
{
|
||||
ownedReader?.Dispose();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ownedCommand?.Dispose();
|
||||
if (wasClosed) cnn.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1706,7 +1717,7 @@ namespace Dapper
|
||||
throw new InvalidOperationException("An enumerable sequence of parameters (arrays, lists, etc) is not allowed in this context");
|
||||
}
|
||||
info = new CacheInfo();
|
||||
if (identity.parametersType != null)
|
||||
if (identity._parametersType != null)
|
||||
{
|
||||
Action<IDbCommand, object> reader;
|
||||
if (exampleParameters is IDynamicParameters)
|
||||
@@ -1723,10 +1734,10 @@ namespace Dapper
|
||||
}
|
||||
else
|
||||
{
|
||||
var literals = GetLiteralTokens(identity.sql);
|
||||
var literals = GetLiteralTokens(identity._sql);
|
||||
reader = CreateParamInfoGenerator(identity, false, true, literals);
|
||||
}
|
||||
if ((identity.commandType == null || identity.commandType == CommandType.Text) && ShouldPassByPosition(identity.sql))
|
||||
if ((identity._commandType == null || identity._commandType == CommandType.Text) && ShouldPassByPosition(identity._sql))
|
||||
{
|
||||
var tail = reader;
|
||||
reader = (cmd, obj) =>
|
||||
@@ -1795,7 +1806,7 @@ namespace Dapper
|
||||
return GetDapperRowDeserializer(reader, startBound, length, returnNullIfFirstMissing);
|
||||
}
|
||||
Type underlyingType = null;
|
||||
if (!(typeMap.ContainsKey(type) || type.IsEnum || type.FullName == LinqBinary
|
||||
if (!(s_typeMap.ContainsKey(type) || type.IsEnum || type.FullName == LinqBinary
|
||||
|| (type.IsValueType && (underlyingType = Nullable.GetUnderlyingType(type)) != null && underlyingType.IsEnum)))
|
||||
{
|
||||
if (typeHandlers.TryGetValue(type, out ITypeHandler handler))
|
||||
@@ -1819,9 +1830,9 @@ namespace Dapper
|
||||
catch { /* don't throw when trying to throw */ }
|
||||
if (hasFields)
|
||||
{
|
||||
#pragma warning disable CA2208 // Instantiate argument exceptions correctly
|
||||
#pragma warning disable CA2208, MA0015 // Instantiate argument exceptions correctly
|
||||
return new ArgumentException("When using the multi-mapping APIs ensure you set the splitOn param if you have keys other than Id", "splitOn");
|
||||
#pragma warning restore CA2208 // Instantiate argument exceptions correctly
|
||||
#pragma warning restore CA2208, MA0015 // Instantiate argument exceptions correctly
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2004,7 +2015,7 @@ namespace Dapper
|
||||
var count = 0;
|
||||
bool isString = value is IEnumerable<string>;
|
||||
bool isDbString = value is IEnumerable<DbString>;
|
||||
DbType dbType = 0;
|
||||
DbType dbType = default;
|
||||
|
||||
int splitAt = SqlMapper.Settings.InListStringSplitCount;
|
||||
bool viaSplit = splitAt >= 0
|
||||
@@ -2026,7 +2037,7 @@ namespace Dapper
|
||||
dbType = LookupDbType(item.GetType(), "", true, out ITypeHandler handler);
|
||||
}
|
||||
}
|
||||
var nextName = namePrefix + count.ToString();
|
||||
var nextName = namePrefix + count.ToString(CultureInfo.InvariantCulture);
|
||||
if (isDbString && item is DbString)
|
||||
{
|
||||
var str = item as DbString;
|
||||
@@ -2063,7 +2074,7 @@ namespace Dapper
|
||||
{
|
||||
count++;
|
||||
var padParam = command.CreateParameter();
|
||||
padParam.ParameterName = namePrefix + count.ToString();
|
||||
padParam.ParameterName = namePrefix + count.ToString(CultureInfo.InvariantCulture);
|
||||
if (isString) padParam.Size = DbString.DefaultLength;
|
||||
padParam.DbType = dbType;
|
||||
padParam.Value = lastValue;
|
||||
@@ -2149,7 +2160,7 @@ namespace Dapper
|
||||
private static bool TryStringSplit<T>(ref IEnumerable<T> list, int splitAt, string namePrefix, IDbCommand command, string colType, bool byPosition,
|
||||
Action<StringBuilder, T> append)
|
||||
{
|
||||
if (!(list is ICollection<T> typed))
|
||||
if (list is not ICollection<T> typed)
|
||||
{
|
||||
typed = list.ToList();
|
||||
list = typed; // because we still need to be able to iterate it, even if we fail here
|
||||
@@ -2374,7 +2385,7 @@ namespace Dapper
|
||||
/// <param name="checkForDuplicates">Whether to check for duplicates.</param>
|
||||
/// <param name="removeUnused">Whether to remove unused parameters.</param>
|
||||
public static Action<IDbCommand, object> CreateParamInfoGenerator(Identity identity, bool checkForDuplicates, bool removeUnused) =>
|
||||
CreateParamInfoGenerator(identity, checkForDuplicates, removeUnused, GetLiteralTokens(identity.sql));
|
||||
CreateParamInfoGenerator(identity, checkForDuplicates, removeUnused, GetLiteralTokens(identity._sql));
|
||||
|
||||
private static bool IsValueTuple(Type type) => (type?.IsValueType == true
|
||||
&& type.FullName.StartsWith("System.ValueTuple`", StringComparison.Ordinal))
|
||||
@@ -2382,7 +2393,7 @@ namespace Dapper
|
||||
|
||||
internal static Action<IDbCommand, object> CreateParamInfoGenerator(Identity identity, bool checkForDuplicates, bool removeUnused, IList<LiteralToken> literals)
|
||||
{
|
||||
Type type = identity.parametersType;
|
||||
Type type = identity._parametersType;
|
||||
|
||||
if (IsValueTuple(type))
|
||||
{
|
||||
@@ -2390,9 +2401,9 @@ namespace Dapper
|
||||
}
|
||||
|
||||
bool filterParams = false;
|
||||
if (removeUnused && identity.commandType.GetValueOrDefault(CommandType.Text) == CommandType.Text)
|
||||
if (removeUnused && identity._commandType.GetValueOrDefault(CommandType.Text) == CommandType.Text)
|
||||
{
|
||||
filterParams = !smellsLikeOleDb.IsMatch(identity.sql);
|
||||
filterParams = !smellsLikeOleDb.IsMatch(identity._sql);
|
||||
}
|
||||
var dm = new DynamicMethod("ParamInfo" + Guid.NewGuid().ToString(), null, new[] { typeof(IDbCommand), typeof(object) }, type, true);
|
||||
|
||||
@@ -2485,7 +2496,7 @@ namespace Dapper
|
||||
}
|
||||
if (filterParams)
|
||||
{
|
||||
props = FilterParameters(props, identity.sql);
|
||||
props = FilterParameters(props, identity._sql);
|
||||
}
|
||||
|
||||
var callOpCode = isStruct ? OpCodes.Call : OpCodes.Callvirt;
|
||||
@@ -2967,9 +2978,9 @@ namespace Dapper
|
||||
/// Gets type-map for the given type
|
||||
/// </summary>
|
||||
/// <returns>Type map instance, default is to create new instance of DefaultTypeMap</returns>
|
||||
#pragma warning disable CA2211 // Non-constant fields should not be visible - I agree with you, but we can't do that until we break the API
|
||||
#pragma warning disable CA2211, MA0069 // Non-constant fields should not be visible - I agree with you, but we can't do that until we break the API
|
||||
public static Func<Type, ITypeMap> TypeMapProvider = (Type type) => new DefaultTypeMap(type);
|
||||
#pragma warning restore CA2211 // Non-constant fields should not be visible
|
||||
#pragma warning restore CA2211, MA0069 // Non-constant fields should not be visible
|
||||
|
||||
/// <summary>
|
||||
/// Gets type-map for the given <see cref="Type"/>.
|
||||
@@ -3648,7 +3659,7 @@ namespace Dapper
|
||||
}
|
||||
else
|
||||
{
|
||||
formattedValue = Convert.ToString(value) + " - " + Type.GetTypeCode(value.GetType());
|
||||
formattedValue = Convert.ToString(value, CultureInfo.InvariantCulture) + " - " + Type.GetTypeCode(value.GetType());
|
||||
}
|
||||
}
|
||||
catch (Exception valEx)
|
||||
@@ -3656,7 +3667,9 @@ namespace Dapper
|
||||
formattedValue = valEx.Message;
|
||||
}
|
||||
}
|
||||
#pragma warning disable MA0076 // do not use implicit culture-sensitive ToString - I'm fine with it in this context
|
||||
toThrow = new DataException($"Error parsing column {index} ({name}={formattedValue})", ex);
|
||||
#pragma warning restore MA0076
|
||||
}
|
||||
catch
|
||||
{ // throw the **original** exception, wrapped as DataException
|
||||
|
||||
@@ -25,7 +25,9 @@ namespace Dapper
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private async static Task<T> ThrowDisposedAsync<T>()
|
||||
{
|
||||
#pragma warning disable MA0042 // use ThrowDisposedAsync - that's us!
|
||||
var result = ThrowDisposed<T>();
|
||||
#pragma warning restore MA0042
|
||||
await Task.Yield(); // will never hit this - already thrown and handled
|
||||
return result;
|
||||
}
|
||||
@@ -213,7 +215,7 @@ namespace Dapper
|
||||
protected override DbDataReader GetDbDataReader(int ordinal) => (((IDataReader)_reader).GetData(ordinal) as DbDataReader) ?? throw new NotSupportedException();
|
||||
}
|
||||
|
||||
internal class BasicWrappedReader : IWrappedDataReader
|
||||
internal sealed class BasicWrappedReader : IWrappedDataReader
|
||||
{
|
||||
private IDataReader _reader;
|
||||
private IDbCommand _cmd;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<RepositoryUrl>https://github.com/StackExchange/Dapper</RepositoryUrl>
|
||||
<Deterministic>false</Deterministic>
|
||||
<NoWarn>$(NOWARN);IDE0056;IDE0057;IDE0079</NoWarn>
|
||||
<NoWarn>$(NOWARN);IDE0056;IDE0057;IDE0079;IDE0090</NoWarn>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>embedded</DebugType>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
|
||||
Reference in New Issue
Block a user