diff --git a/src/ServiceStack.OrmLite/Dapper/CommandDefinition.cs b/src/ServiceStack.OrmLite/Dapper/CommandDefinition.cs
index 8998d96d9..25217dd1c 100644
--- a/src/ServiceStack.OrmLite/Dapper/CommandDefinition.cs
+++ b/src/ServiceStack.OrmLite/Dapper/CommandDefinition.cs
@@ -76,11 +76,16 @@ internal void OnCompleted()
///
/// Initialize the command definition
///
+ /// The text for this command.
+ /// The parameters for this command.
+ /// The transaction for this command to participate in.
+ /// The timeout (in seconds) for this command.
+ /// The for this command.
+ /// The behavior flags for this command.
+ /// The cancellation token for this command.
public CommandDefinition(string commandText, object parameters = null, IDbTransaction transaction = null, int? commandTimeout = null,
CommandType? commandType = null, CommandFlags flags = CommandFlags.Buffered
-#if ASYNC
, CancellationToken cancellationToken = default(CancellationToken)
-#endif
)
{
CommandText = commandText;
@@ -89,9 +94,7 @@ internal void OnCompleted()
CommandTimeout = commandTimeout;
CommandType = commandType;
Flags = flags;
-#if ASYNC
CancellationToken = cancellationToken;
-#endif
}
private CommandDefinition(object parameters) : this()
@@ -99,13 +102,10 @@ private CommandDefinition(object parameters) : this()
Parameters = parameters;
}
-#if ASYNC
-
///
/// For asynchronous operations, the cancellation-token
///
public CancellationToken CancellationToken { get; }
-#endif
internal IDbCommand SetupCommand(IDbConnection cnn, Action paramReader)
{
@@ -135,8 +135,7 @@ private static Action GetInit(Type commandType)
{
if (commandType == null)
return null; // GIGO
- Action action;
- if (SqlMapper.Link>.TryGet(commandInitCache, commandType, out action))
+ if (SqlMapper.Link>.TryGet(commandInitCache, commandType, out Action action))
{
return action;
}
@@ -176,12 +175,11 @@ private static Action GetInit(Type commandType)
private static MethodInfo GetBasicPropertySetter(Type declaringType, string name, Type expectedType)
{
var prop = declaringType.GetProperty(name, BindingFlags.Public | BindingFlags.Instance);
- if (prop != null && prop.CanWrite && prop.PropertyType == expectedType && prop.GetIndexParameters().Length == 0)
+ if (prop?.CanWrite == true && prop.PropertyType == expectedType && prop.GetIndexParameters().Length == 0)
{
return prop.GetSetMethod();
}
return null;
}
}
-
}
diff --git a/src/ServiceStack.OrmLite/Dapper/CommandFlags.cs b/src/ServiceStack.OrmLite/Dapper/CommandFlags.cs
index cc5c08020..12141516b 100644
--- a/src/ServiceStack.OrmLite/Dapper/CommandFlags.cs
+++ b/src/ServiceStack.OrmLite/Dapper/CommandFlags.cs
@@ -2,7 +2,6 @@
namespace ServiceStack.OrmLite.Dapper
{
-
///
/// Additional state flags that control command behaviour
///
@@ -26,5 +25,4 @@ public enum CommandFlags
///
NoCache = 4,
}
-
}
diff --git a/src/ServiceStack.OrmLite/Dapper/CustomPropertyTypeMap.cs b/src/ServiceStack.OrmLite/Dapper/CustomPropertyTypeMap.cs
index 5f97aa30b..3baf6c2a6 100644
--- a/src/ServiceStack.OrmLite/Dapper/CustomPropertyTypeMap.cs
+++ b/src/ServiceStack.OrmLite/Dapper/CustomPropertyTypeMap.cs
@@ -3,7 +3,6 @@
namespace ServiceStack.OrmLite.Dapper
{
-
///
/// Implements custom property mapping by user provided criteria (usually presence of some custom attribute with column to member mapping)
///
@@ -19,14 +18,8 @@ public sealed class CustomPropertyTypeMap : SqlMapper.ITypeMap
/// Property selector based on target type and DataReader column name
public CustomPropertyTypeMap(Type type, Func propertySelector)
{
- if (type == null)
- throw new ArgumentNullException(nameof(type));
-
- if (propertySelector == null)
- throw new ArgumentNullException(nameof(propertySelector));
-
- _type = type;
- _propertySelector = propertySelector;
+ _type = type ?? throw new ArgumentNullException(nameof(type));
+ _propertySelector = propertySelector ?? throw new ArgumentNullException(nameof(propertySelector));
}
///
@@ -35,19 +28,14 @@ public CustomPropertyTypeMap(Type type, Func propert
/// DataReader column names
/// DataReader column types
/// Default constructor
- public ConstructorInfo FindConstructor(string[] names, Type[] types)
- {
- return _type.GetConstructor(new Type[0]);
- }
+ public ConstructorInfo FindConstructor(string[] names, Type[] types) =>
+ _type.GetConstructor(new Type[0]);
///
/// Always returns null
///
///
- public ConstructorInfo FindExplicitConstructor()
- {
- return null;
- }
+ public ConstructorInfo FindExplicitConstructor() => null;
///
/// Not implemented as far as default constructor used for all cases
diff --git a/src/ServiceStack.OrmLite/Dapper/DataTableHandler.cs b/src/ServiceStack.OrmLite/Dapper/DataTableHandler.cs
index 8bc6a9b06..a0bc5ca2b 100644
--- a/src/ServiceStack.OrmLite/Dapper/DataTableHandler.cs
+++ b/src/ServiceStack.OrmLite/Dapper/DataTableHandler.cs
@@ -1,9 +1,9 @@
using System;
using System.Data;
-#if !NETSTANDARD2_0
+#if !NETSTANDARD1_3
namespace ServiceStack.OrmLite.Dapper
{
- sealed class DataTableHandler : SqlMapper.ITypeHandler
+ internal sealed class DataTableHandler : SqlMapper.ITypeHandler
{
public object Parse(Type destinationType, object value)
{
diff --git a/src/ServiceStack.OrmLite/Dapper/DbString.cs b/src/ServiceStack.OrmLite/Dapper/DbString.cs
index 8061fcaca..5db82d624 100644
--- a/src/ServiceStack.OrmLite/Dapper/DbString.cs
+++ b/src/ServiceStack.OrmLite/Dapper/DbString.cs
@@ -55,8 +55,17 @@ public void AddParameter(IDbCommand command, string name)
{
throw new InvalidOperationException("If specifying IsFixedLength, a Length must also be specified");
}
- var param = command.CreateParameter();
- param.ParameterName = name;
+ bool add = !command.Parameters.Contains(name);
+ IDbDataParameter param;
+ if (add)
+ {
+ param = command.CreateParameter();
+ param.ParameterName = name;
+ }
+ else
+ {
+ param = (IDbDataParameter)command.Parameters[name];
+ }
#pragma warning disable 0618
param.Value = SqlMapper.SanitizeParameterValue(Value);
#pragma warning restore 0618
@@ -69,7 +78,10 @@ public void AddParameter(IDbCommand command, string name)
param.Size = Length;
}
param.DbType = IsAnsi ? (IsFixedLength ? DbType.AnsiStringFixedLength : DbType.AnsiString) : (IsFixedLength ? DbType.StringFixedLength : DbType.String);
- command.Parameters.Add(param);
+ if (add)
+ {
+ command.Parameters.Add(param);
+ }
}
}
}
diff --git a/src/ServiceStack.OrmLite/Dapper/DefaultTypeMap.cs b/src/ServiceStack.OrmLite/Dapper/DefaultTypeMap.cs
index f2a36d3b3..53b68b6cb 100644
--- a/src/ServiceStack.OrmLite/Dapper/DefaultTypeMap.cs
+++ b/src/ServiceStack.OrmLite/Dapper/DefaultTypeMap.cs
@@ -26,8 +26,8 @@ public DefaultTypeMap(Type type)
Properties = GetSettableProps(type);
_type = type;
}
-#if NETSTANDARD2_0
- static bool IsParameterMatch(ParameterInfo[] x, ParameterInfo[] y)
+#if NETSTANDARD1_3
+ private static bool IsParameterMatch(ParameterInfo[] x, ParameterInfo[] y)
{
if (ReferenceEquals(x, y)) return true;
if (x == null || y == null) return false;
@@ -40,7 +40,7 @@ static bool IsParameterMatch(ParameterInfo[] x, ParameterInfo[] y)
internal static MethodInfo GetPropertySetter(PropertyInfo propertyInfo, Type type)
{
if (propertyInfo.DeclaringType == type) return propertyInfo.GetSetMethod(true);
-#if NETSTANDARD2_0
+#if NETSTANDARD1_3
return propertyInfo.DeclaringType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Single(x => x.Name == propertyInfo.Name
&& x.PropertyType == propertyInfo.PropertyType
@@ -91,15 +91,15 @@ public ConstructorInfo FindConstructor(string[] names, Type[] types)
int i = 0;
for (; i < ctorParameters.Length; i++)
{
- if (!String.Equals(ctorParameters[i].Name, names[i], StringComparison.OrdinalIgnoreCase))
+ if (!string.Equals(ctorParameters[i].Name, names[i], StringComparison.OrdinalIgnoreCase))
break;
if (types[i] == typeof(byte[]) && ctorParameters[i].ParameterType.FullName == SqlMapper.LinqBinary)
continue;
var unboxedType = Nullable.GetUnderlyingType(ctorParameters[i].ParameterType) ?? ctorParameters[i].ParameterType;
if ((unboxedType != types[i] && !SqlMapper.HasTypeHandler(unboxedType))
- && !(unboxedType.IsEnum && Enum.GetUnderlyingType(unboxedType) == types[i])
+ && !(unboxedType.IsEnum() && Enum.GetUnderlyingType(unboxedType) == types[i])
&& !(unboxedType == typeof(char) && types[i] == typeof(string))
- && !(unboxedType.IsEnum && types[i] == typeof(string)))
+ && !(unboxedType.IsEnum() && types[i] == typeof(string)))
{
break;
}
@@ -118,7 +118,7 @@ public ConstructorInfo FindConstructor(string[] names, Type[] types)
public ConstructorInfo FindExplicitConstructor()
{
var constructors = _type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
-#if NETSTANDARD2_0
+#if NETSTANDARD1_3
var withAttr = constructors.Where(c => c.CustomAttributes.Any(x => x.AttributeType == typeof(ExplicitConstructorAttribute))).ToList();
#else
var withAttr = constructors.Where(c => c.GetCustomAttributes(typeof(ExplicitConstructorAttribute), true).Length > 0).ToList();
@@ -152,13 +152,13 @@ public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor,
/// Mapping implementation
public SqlMapper.IMemberMap GetMember(string columnName)
{
- var property = Properties.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.Ordinal))
- ?? Properties.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase));
+ var property = Properties.Find(p => string.Equals(p.Name, columnName, StringComparison.Ordinal))
+ ?? Properties.Find(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase));
if (property == null && MatchNamesWithUnderscores)
{
- property = Properties.FirstOrDefault(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.Ordinal))
- ?? Properties.FirstOrDefault(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.OrdinalIgnoreCase));
+ property = Properties.Find(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.Ordinal))
+ ?? Properties.Find(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.OrdinalIgnoreCase));
}
if (property != null)
@@ -169,20 +169,20 @@ public SqlMapper.IMemberMap GetMember(string columnName)
// preference order is:
// exact match over underscre match, exact case over wrong case, backing fields over regular fields, match-inc-underscores over match-exc-underscores
- var field = _fields.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.Ordinal))
- ?? _fields.FirstOrDefault(p => string.Equals(p.Name, backingFieldName, StringComparison.Ordinal))
- ?? _fields.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase))
- ?? _fields.FirstOrDefault(p => string.Equals(p.Name, backingFieldName, StringComparison.OrdinalIgnoreCase));
+ var field = _fields.Find(p => string.Equals(p.Name, columnName, StringComparison.Ordinal))
+ ?? _fields.Find(p => string.Equals(p.Name, backingFieldName, StringComparison.Ordinal))
+ ?? _fields.Find(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase))
+ ?? _fields.Find(p => string.Equals(p.Name, backingFieldName, StringComparison.OrdinalIgnoreCase));
if (field == null && MatchNamesWithUnderscores)
{
var effectiveColumnName = columnName.Replace("_", "");
- backingFieldName = "<" +effectiveColumnName + ">k__BackingField";
+ backingFieldName = "<" + effectiveColumnName + ">k__BackingField";
- field = _fields.FirstOrDefault(p => string.Equals(p.Name, effectiveColumnName, StringComparison.Ordinal))
- ?? _fields.FirstOrDefault(p => string.Equals(p.Name, backingFieldName, StringComparison.Ordinal))
- ?? _fields.FirstOrDefault(p => string.Equals(p.Name, effectiveColumnName, StringComparison.OrdinalIgnoreCase))
- ?? _fields.FirstOrDefault(p => string.Equals(p.Name, backingFieldName, StringComparison.OrdinalIgnoreCase));
+ field = _fields.Find(p => string.Equals(p.Name, effectiveColumnName, StringComparison.Ordinal))
+ ?? _fields.Find(p => string.Equals(p.Name, backingFieldName, StringComparison.Ordinal))
+ ?? _fields.Find(p => string.Equals(p.Name, effectiveColumnName, StringComparison.OrdinalIgnoreCase))
+ ?? _fields.Find(p => string.Equals(p.Name, backingFieldName, StringComparison.OrdinalIgnoreCase));
}
if (field != null)
diff --git a/src/ServiceStack.OrmLite/Dapper/DynamicParameters.CachedOutputSetters.cs b/src/ServiceStack.OrmLite/Dapper/DynamicParameters.CachedOutputSetters.cs
index 46eb7d1ea..ce9117007 100644
--- a/src/ServiceStack.OrmLite/Dapper/DynamicParameters.CachedOutputSetters.cs
+++ b/src/ServiceStack.OrmLite/Dapper/DynamicParameters.CachedOutputSetters.cs
@@ -2,7 +2,7 @@
namespace ServiceStack.OrmLite.Dapper
{
- partial class DynamicParameters
+ public partial class DynamicParameters
{
// The type here is used to differentiate the cache by type via generics
// ReSharper disable once UnusedTypeParameter
diff --git a/src/ServiceStack.OrmLite/Dapper/DynamicParameters.ParamInfo.cs b/src/ServiceStack.OrmLite/Dapper/DynamicParameters.ParamInfo.cs
index 18bf007f4..4e9d41f61 100644
--- a/src/ServiceStack.OrmLite/Dapper/DynamicParameters.ParamInfo.cs
+++ b/src/ServiceStack.OrmLite/Dapper/DynamicParameters.ParamInfo.cs
@@ -3,9 +3,9 @@
namespace ServiceStack.OrmLite.Dapper
{
- partial class DynamicParameters
+ public partial class DynamicParameters
{
- sealed class ParamInfo
+ private sealed class ParamInfo
{
public string Name { get; set; }
public object Value { get; set; }
diff --git a/src/ServiceStack.OrmLite/Dapper/DynamicParameters.cs b/src/ServiceStack.OrmLite/Dapper/DynamicParameters.cs
index 6494f931d..7aed219eb 100644
--- a/src/ServiceStack.OrmLite/Dapper/DynamicParameters.cs
+++ b/src/ServiceStack.OrmLite/Dapper/DynamicParameters.cs
@@ -6,33 +6,24 @@
using System.Reflection;
using System.Reflection.Emit;
-#if NETSTANDARD2_0
+#if NETSTANDARD1_3
using ApplicationException = System.InvalidOperationException;
#endif
namespace ServiceStack.OrmLite.Dapper
{
-
///
/// A bag of parameters that can be passed to the Dapper Query and Execute methods
///
public partial class DynamicParameters : SqlMapper.IDynamicParameters, SqlMapper.IParameterLookup, SqlMapper.IParameterCallbacks
{
internal const DbType EnumerableMultiParameter = (DbType)(-1);
- static Dictionary> paramReaderCache = new Dictionary>();
-
- Dictionary parameters = new Dictionary();
- List
/// Note: each row can be accessed via "dynamic", or by casting to an IDictionary<string,object>
- public Task> ReadAsync(bool buffered = true)
- {
- return ReadAsyncImpl(typeof(DapperRow), buffered);
- }
+ /// Whether to buffer the results.
+ public Task> ReadAsync(bool buffered = true) => ReadAsyncImpl(typeof(DapperRow), buffered);
///
/// Read an individual row of the next grid of results, returned as a dynamic object
///
/// Note: the row can be accessed via "dynamic", or by casting to an IDictionary<string,object>
- public Task ReadFirstAsync()
- {
- return ReadRowAsyncImpl(typeof(DapperRow), Row.First);
- }
+ public Task ReadFirstAsync() => ReadRowAsyncImpl(typeof(DapperRow), Row.First);
+
///
/// Read an individual row of the next grid of results, returned as a dynamic object
///
/// Note: the row can be accessed via "dynamic", or by casting to an IDictionary<string,object>
- public Task ReadFirstOrDefaultAsync()
- {
- return ReadRowAsyncImpl(typeof(DapperRow), Row.FirstOrDefault);
- }
+ public Task ReadFirstOrDefaultAsync() => ReadRowAsyncImpl(typeof(DapperRow), Row.FirstOrDefault);
+
///
/// Read an individual row of the next grid of results, returned as a dynamic object
///
/// Note: the row can be accessed via "dynamic", or by casting to an IDictionary<string,object>
- public Task ReadSingleAsync()
- {
- return ReadRowAsyncImpl(typeof(DapperRow), Row.Single);
- }
+ public Task ReadSingleAsync() => ReadRowAsyncImpl(typeof(DapperRow), Row.Single);
+
///
/// Read an individual row of the next grid of results, returned as a dynamic object
///
/// Note: the row can be accessed via "dynamic", or by casting to an IDictionary<string,object>
- public Task ReadSingleOrDefaultAsync()
- {
- return ReadRowAsyncImpl(typeof(DapperRow), Row.SingleOrDefault);
- }
+ public Task ReadSingleOrDefaultAsync() => ReadRowAsyncImpl(typeof(DapperRow), Row.SingleOrDefault);
///
/// Read the next grid of results
///
+ /// The type to read.
+ /// Whether to buffer the results.
+ /// is null.
public Task> ReadAsync(Type type, bool buffered = true)
{
if (type == null) throw new ArgumentNullException(nameof(type));
@@ -74,30 +65,41 @@ public Task> ReadAsync(Type type, bool buffered = true)
///
/// Read an individual row of the next grid of results
///
+ /// The type to read.
+ /// is null.
public Task ReadFirstAsync(Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
return ReadRowAsyncImpl(type, Row.First);
}
+
///
- /// Read an individual row of the next grid of results
+ /// Read an individual row of the next grid of results.
///
+ /// The type to read.
+ /// is null.
public Task ReadFirstOrDefaultAsync(Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
return ReadRowAsyncImpl(type, Row.FirstOrDefault);
}
+
///
- /// Read an individual row of the next grid of results
+ /// Read an individual row of the next grid of results.
///
+ /// The type to read.
+ /// is null.
public Task ReadSingleAsync(Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
return ReadRowAsyncImpl(type, Row.Single);
}
+
///
- /// Read an individual row of the next grid of results
+ /// Read an individual row of the next grid of results.
///
+ /// The type to read.
+ /// is null.
public Task ReadSingleOrDefaultAsync(Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
@@ -105,41 +107,35 @@ public Task ReadSingleOrDefaultAsync(Type type)
}
///
- /// Read the next grid of results
+ /// Read the next grid of results.
///
- public Task> ReadAsync(bool buffered = true)
- {
- return ReadAsyncImpl(typeof(T), buffered);
- }
+ /// The type to read.
+ /// Whether the results should be buffered in memory.
+ public Task> ReadAsync(bool buffered = true) => ReadAsyncImpl(typeof(T), buffered);
///
- /// Read an individual row of the next grid of results
+ /// Read an individual row of the next grid of results.
///
- public Task ReadFirstAsync()
- {
- return ReadRowAsyncImpl(typeof(T), Row.First);
- }
+ /// The type to read.
+ public Task ReadFirstAsync() => ReadRowAsyncImpl(typeof(T), Row.First);
+
///
- /// Read an individual row of the next grid of results
+ /// Read an individual row of the next grid of results.
///
- public Task ReadFirstOrDefaultAsync()
- {
- return ReadRowAsyncImpl(typeof(T), Row.FirstOrDefault);
- }
+ /// The type to read.
+ public Task ReadFirstOrDefaultAsync() => ReadRowAsyncImpl(typeof(T), Row.FirstOrDefault);
+
///
- /// Read an individual row of the next grid of results
+ /// Read an individual row of the next grid of results.
///
- public Task ReadSingleAsync()
- {
- return ReadRowAsyncImpl(typeof(T), Row.Single);
- }
+ /// The type to read.
+ public Task ReadSingleAsync() => ReadRowAsyncImpl(typeof(T), Row.Single);
+
///
- /// Read an individual row of the next grid of results
+ /// Read an individual row of the next grid of results.
///
- public Task ReadSingleOrDefaultAsync()
- {
- return ReadRowAsyncImpl(typeof(T), Row.SingleOrDefault);
- }
+ /// The type to read.
+ public Task ReadSingleOrDefaultAsync() => ReadRowAsyncImpl(typeof(T), Row.SingleOrDefault);
private async Task NextResultAsync()
{
@@ -177,11 +173,11 @@ private Task> ReadAsyncImpl(Type type, bool buffered)
IsConsumed = true;
if (buffered && reader is DbDataReader)
{
- return ReadBufferedAsync(gridIndex, deserializer.Func, typedIdentity);
+ return ReadBufferedAsync(gridIndex, deserializer.Func);
}
else
{
- var result = ReadDeferred(gridIndex, deserializer.Func, typedIdentity, type);
+ var result = ReadDeferred(gridIndex, deserializer.Func, type);
if (buffered) result = result.ToList(); // for the "not a DbDataReader" scenario
return Task.FromResult(result);
}
@@ -189,11 +185,10 @@ private Task> ReadAsyncImpl(Type type, bool buffered)
private Task ReadRowAsyncImpl(Type type, Row row)
{
- var dbReader = reader as DbDataReader;
- if (dbReader != null) return ReadRowAsyncImplViaDbReader(dbReader, type, row);
+ if (reader is DbDataReader dbReader) return ReadRowAsyncImplViaDbReader(dbReader, type, row);
// no async API available; use non-async and fake it
- return Task.FromResult(ReadRow(type, row));
+ return Task.FromResult(ReadRow(type, row));
}
private async Task ReadRowAsyncImplViaDbReader(DbDataReader reader, Type type, Row row)
@@ -217,7 +212,7 @@ private async Task ReadRowAsyncImplViaDbReader(DbDataReader reader, Type t
}
result = (T)deserializer.Func(reader);
if ((row & Row.Single) != 0 && await reader.ReadAsync(cancel).ConfigureAwait(false)) ThrowMultipleRows(row);
- while (await reader.ReadAsync(cancel).ConfigureAwait(false)) { }
+ while (await reader.ReadAsync(cancel).ConfigureAwait(false)) { /* ignore subsequent rows */ }
}
else if ((row & Row.FirstOrDefault) == 0) // demanding a row, and don't have one
{
@@ -227,12 +222,12 @@ private async Task ReadRowAsyncImplViaDbReader(DbDataReader reader, Type t
return result;
}
- private async Task> ReadBufferedAsync(int index, Func deserializer, Identity typedIdentity)
+ private async Task> ReadBufferedAsync(int index, Func deserializer)
{
try
{
var reader = (DbDataReader)this.reader;
- List buffer = new List();
+ var buffer = new List();
while (index == gridIndex && await reader.ReadAsync(cancel).ConfigureAwait(false))
{
buffer.Add((T)deserializer(reader));
@@ -248,7 +243,5 @@ private async Task> ReadBufferedAsync(int index, Func
/// The grid reader provides interfaces for reading multiple result sets from a Dapper query
@@ -13,8 +13,8 @@ partial class SqlMapper
public partial class GridReader : IDisposable
{
private IDataReader reader;
- private Identity identity;
- private bool addToCache;
+ private readonly Identity identity;
+ private readonly bool addToCache;
internal GridReader(IDbCommand command, IDataReader reader, Identity identity, IParameterCallbacks callbacks, bool addToCache)
{
@@ -26,87 +26,73 @@ internal GridReader(IDbCommand command, IDataReader reader, Identity identity, I
}
///
- /// Read the next grid of results, returned as a dynamic object
+ /// Read the next grid of results, returned as a dynamic object.
///
+ /// Whether the results should be buffered in memory.
/// Note: each row can be accessed via "dynamic", or by casting to an IDictionary<string,object>
- public IEnumerable Read(bool buffered = true)
- {
- return ReadImpl(typeof(DapperRow), buffered);
- }
+ public IEnumerable Read(bool buffered = true) => ReadImpl(typeof(DapperRow), buffered);
///
- /// Read an individual row of the next grid of results, returned as a dynamic object
+ /// Read an individual row of the next grid of results, returned as a dynamic object.
///
/// Note: the row can be accessed via "dynamic", or by casting to an IDictionary<string,object>
- public dynamic ReadFirst()
- {
- return ReadRow(typeof(DapperRow), Row.First);
- }
+ public dynamic ReadFirst() => ReadRow(typeof(DapperRow), Row.First);
+
///
- /// Read an individual row of the next grid of results, returned as a dynamic object
+ /// Read an individual row of the next grid of results, returned as a dynamic object.
///
/// Note: the row can be accessed via "dynamic", or by casting to an IDictionary<string,object>
- public dynamic ReadFirstOrDefault()
- {
- return ReadRow(typeof(DapperRow), Row.FirstOrDefault);
- }
+ public dynamic ReadFirstOrDefault() => ReadRow(typeof(DapperRow), Row.FirstOrDefault);
+
///
- /// Read an individual row of the next grid of results, returned as a dynamic object
+ /// Read an individual row of the next grid of results, returned as a dynamic object.
///
/// Note: the row can be accessed via "dynamic", or by casting to an IDictionary<string,object>
- public dynamic ReadSingle()
- {
- return ReadRow(typeof(DapperRow), Row.Single);
- }
+ public dynamic ReadSingle() => ReadRow(typeof(DapperRow), Row.Single);
+
///
- /// Read an individual row of the next grid of results, returned as a dynamic object
+ /// Read an individual row of the next grid of results, returned as a dynamic object.
///
/// Note: the row can be accessed via "dynamic", or by casting to an IDictionary<string,object>
- public dynamic ReadSingleOrDefault()
- {
- return ReadRow(typeof(DapperRow), Row.SingleOrDefault);
- }
+ public dynamic ReadSingleOrDefault() => ReadRow(typeof(DapperRow), Row.SingleOrDefault);
///
- /// Read the next grid of results
+ /// Read the next grid of results.
///
- public IEnumerable Read(bool buffered = true)
- {
- return ReadImpl(typeof(T), buffered);
- }
+ /// The type to read.
+ /// Whether the results should be buffered in memory.
+ public IEnumerable Read(bool buffered = true) => ReadImpl(typeof(T), buffered);
///
- /// Read an individual row of the next grid of results
+ /// Read an individual row of the next grid of results.
///
- public T ReadFirst()
- {
- return ReadRow(typeof(T), Row.First);
- }
+ /// The type to read.
+ public T ReadFirst() => ReadRow(typeof(T), Row.First);
+
///
- /// Read an individual row of the next grid of results
+ /// Read an individual row of the next grid of results.
///
- public T ReadFirstOrDefault()
- {
- return ReadRow(typeof(T), Row.FirstOrDefault);
- }
+ /// The type to read.
+ public T ReadFirstOrDefault() => ReadRow(typeof(T), Row.FirstOrDefault);
+
///
- /// Read an individual row of the next grid of results
+ /// Read an individual row of the next grid of results.
///
- public T ReadSingle()
- {
- return ReadRow(typeof(T), Row.Single);
- }
+ /// The type to read.
+ public T ReadSingle() => ReadRow(typeof(T), Row.Single);
+
///
- /// Read an individual row of the next grid of results
+ /// Read an individual row of the next grid of results.
///
- public T ReadSingleOrDefault()
- {
- return ReadRow(typeof(T), Row.SingleOrDefault);
- }
+ /// The type to read.
+ public T ReadSingleOrDefault() => ReadRow(typeof(T), Row.SingleOrDefault);
///
- /// Read the next grid of results
+ /// Read the next grid of results.
///
+ /// The type to read.
+ /// Whether to buffer the results.
+ /// is null.
public IEnumerable Read(Type type, bool buffered = true)
{
if (type == null) throw new ArgumentNullException(nameof(type));
@@ -114,32 +100,43 @@ public IEnumerable Read(Type type, bool buffered = true)
}
///
- /// Read an individual row of the next grid of results
+ /// Read an individual row of the next grid of results.
///
+ /// The type to read.
+ /// is null.
public object ReadFirst(Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
return ReadRow(type, Row.First);
}
+
///
- /// Read an individual row of the next grid of results
+ /// Read an individual row of the next grid of results.
///
+ /// The type to read.
+ /// is null.
public object ReadFirstOrDefault(Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
return ReadRow(type, Row.FirstOrDefault);
}
+
///
- /// Read an individual row of the next grid of results
+ /// Read an individual row of the next grid of results.
///
+ /// The type to read.
+ /// is null.
public object ReadSingle(Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
return ReadRow(type, Row.Single);
}
+
///
- /// Read an individual row of the next grid of results
+ /// Read an individual row of the next grid of results.
///
+ /// The type to read.
+ /// is null.
public object ReadSingleOrDefault(Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
@@ -161,7 +158,7 @@ private IEnumerable ReadImpl(Type type, bool buffered)
cache.Deserializer = deserializer;
}
IsConsumed = true;
- var result = ReadDeferred(gridIndex, deserializer.Func, typedIdentity, type);
+ var result = ReadDeferred(gridIndex, deserializer.Func, type);
return buffered ? result.ToList() : result;
}
@@ -172,7 +169,7 @@ private T ReadRow(Type type, Row row)
IsConsumed = true;
T result = default(T);
- if(reader.Read() && reader.FieldCount != 0)
+ if (reader.Read() && reader.FieldCount != 0)
{
var typedIdentity = identity.ForGrid(type, gridIndex);
CacheInfo cache = GetCacheInfo(typedIdentity, null, addToCache);
@@ -185,17 +182,19 @@ private T ReadRow(Type type, Row row)
cache.Deserializer = deserializer;
}
object val = deserializer.Func(reader);
- if(val == null || val is T)
+ if (val == null || val is T)
{
result = (T)val;
- } else {
+ }
+ else
+ {
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()) { }
+ while (reader.Read()) { /* ignore subsequent rows */ }
}
- else if((row & Row.FirstOrDefault) == 0) // demanding a row, and don't have one
+ else if ((row & Row.FirstOrDefault) == 0) // demanding a row, and don't have one
{
ThrowZeroRows(row);
}
@@ -203,7 +202,6 @@ private T ReadRow(Type type, Row row)
return result;
}
-
private IEnumerable MultiReadInternal(Delegate func, string splitOn)
{
var identity = this.identity.ForGrid(typeof(TReturn), new Type[] {
@@ -215,6 +213,9 @@ private T ReadRow(Type type, Row row)
typeof(TSixth),
typeof(TSeventh)
}, gridIndex);
+
+ IsConsumed = true;
+
try
{
foreach (var r in MultiMapImpl(null, default(CommandDefinition), func, splitOn, reader, identity, false))
@@ -245,8 +246,14 @@ private IEnumerable MultiReadInternal(Type[] types, Func
- /// Read multiple objects from a single record set on the grid
+ /// Read multiple objects from a single record set on the grid.
///
+ /// The first type in the record set.
+ /// The second type in the record set.
+ /// The type to return from the record set.
+ /// The mapping function from the read types to the return type.
+ /// The field(s) we should split and read the second object from (defaults to "id")
+ /// Whether to buffer results in memory.
public IEnumerable Read(Func func, string splitOn = "id", bool buffered = true)
{
var result = MultiReadInternal(func, splitOn);
@@ -254,8 +261,15 @@ private IEnumerable MultiReadInternal(Type[] types, Func
- /// Read multiple objects from a single record set on the grid
+ /// Read multiple objects from a single record set on the grid.
///
+ /// The first type in the record set.
+ /// The second type in the record set.
+ /// The third type in the record set.
+ /// The type to return from the record set.
+ /// The mapping function from the read types to the return type.
+ /// The field(s) we should split and read the second object from (defaults to "id")
+ /// Whether to buffer results in memory.
public IEnumerable Read(Func func, string splitOn = "id", bool buffered = true)
{
var result = MultiReadInternal(func, splitOn);
@@ -265,6 +279,14 @@ private IEnumerable MultiReadInternal(Type[] types, Func
/// Read multiple objects from a single record set on the grid
///
+ /// The first type in the record set.
+ /// The second type in the record set.
+ /// The third type in the record set.
+ /// The fourth type in the record set.
+ /// The type to return from the record set.
+ /// The mapping function from the read types to the return type.
+ /// The field(s) we should split and read the second object from (defaults to "id")
+ /// Whether to buffer results in memory.
public IEnumerable Read(Func func, string splitOn = "id", bool buffered = true)
{
var result = MultiReadInternal(func, splitOn);
@@ -274,22 +296,54 @@ private IEnumerable MultiReadInternal(Type[] types, Func
/// Read multiple objects from a single record set on the grid
///
+ /// The first type in the record set.
+ /// The second type in the record set.
+ /// The third type in the record set.
+ /// The fourth type in the record set.
+ /// The fifth type in the record set.
+ /// The type to return from the record set.
+ /// The mapping function from the read types to the return type.
+ /// The field(s) we should split and read the second object from (defaults to "id")
+ /// Whether to buffer results in memory.
public IEnumerable Read(Func func, string splitOn = "id", bool buffered = true)
{
var result = MultiReadInternal(func, splitOn);
return buffered ? result.ToList() : result;
}
+
///
/// Read multiple objects from a single record set on the grid
///
+ /// The first type in the record set.
+ /// The second type in the record set.
+ /// The third type in the record set.
+ /// The fourth type in the record set.
+ /// The fifth type in the record set.
+ /// The sixth type in the record set.
+ /// The type to return from the record set.
+ /// The mapping function from the read types to the return type.
+ /// The field(s) we should split and read the second object from (defaults to "id")
+ /// Whether to buffer results in memory.
public IEnumerable Read(Func func, string splitOn = "id", bool buffered = true)
{
var result = MultiReadInternal(func, splitOn);
return buffered ? result.ToList() : result;
}
+
///
/// Read multiple objects from a single record set on the grid
///
+ /// The first type in the record set.
+ /// The second type in the record set.
+ /// The third type in the record set.
+ /// The fourth type in the record set.
+ /// The fifth type in the record set.
+ /// The sixth type in the record set.
+ /// The seventh type in the record set.
+ /// The type to return from the record set.
+ /// The mapping function from the read types to the return type.
+ /// The field(s) we should split and read the second object from (defaults to "id")
+ /// Whether to buffer results in memory.
public IEnumerable Read(Func func, string splitOn = "id", bool buffered = true)
{
var result = MultiReadInternal(func, splitOn);
@@ -299,13 +353,18 @@ private IEnumerable MultiReadInternal(Type[] types, Func
/// Read multiple objects from a single record set on the grid
///
+ /// The type to return from the record set.
+ /// The types to read from the result set.
+ /// The mapping function from the read types to the return type.
+ /// The field(s) we should split and read the second object from (defaults to "id")
+ /// Whether to buffer results in memory.
public IEnumerable Read(Type[] types, Func map, string splitOn = "id", bool buffered = true)
{
- var result = MultiReadInternal(types, map, splitOn);
+ var result = MultiReadInternal(types, map, splitOn);
return buffered ? result.ToList() : result;
}
- private IEnumerable ReadDeferred(int index, Func deserializer, Identity typedIdentity, Type effectiveType)
+ private IEnumerable ReadDeferred(int index, Func deserializer, Type effectiveType)
{
try
{
@@ -313,9 +372,12 @@ private IEnumerable ReadDeferred(int index, Func dese
while (index == gridIndex && reader.Read())
{
object val = deserializer(reader);
- if (val == null || val is T) {
+ if (val == null || val is T)
+ {
yield return (T)val;
- } else {
+ }
+ else
+ {
yield return (T)Convert.ChangeType(val, convertToType, CultureInfo.InvariantCulture);
}
}
@@ -328,8 +390,9 @@ private IEnumerable ReadDeferred(int index, Func dese
}
}
}
+
private int gridIndex, readCount;
- private IParameterCallbacks callbacks;
+ private readonly IParameterCallbacks callbacks;
///
/// Has the underlying reader been consumed?
@@ -359,6 +422,7 @@ private void NextResult()
Dispose();
}
}
+
///
/// Dispose the grid, closing and disposing both the underlying reader and command.
///
diff --git a/src/ServiceStack.OrmLite/Dapper/SqlMapper.ICustomQueryParameter.cs b/src/ServiceStack.OrmLite/Dapper/SqlMapper.ICustomQueryParameter.cs
index c2b857007..54b9f905c 100644
--- a/src/ServiceStack.OrmLite/Dapper/SqlMapper.ICustomQueryParameter.cs
+++ b/src/ServiceStack.OrmLite/Dapper/SqlMapper.ICustomQueryParameter.cs
@@ -2,7 +2,7 @@
namespace ServiceStack.OrmLite.Dapper
{
- partial class SqlMapper
+ public static partial class SqlMapper
{
///
/// Implement this interface to pass an arbitrary db specific parameter to Dapper
diff --git a/src/ServiceStack.OrmLite/Dapper/SqlMapper.IDataReader.cs b/src/ServiceStack.OrmLite/Dapper/SqlMapper.IDataReader.cs
index a15b24a10..0d9583ddd 100644
--- a/src/ServiceStack.OrmLite/Dapper/SqlMapper.IDataReader.cs
+++ b/src/ServiceStack.OrmLite/Dapper/SqlMapper.IDataReader.cs
@@ -4,14 +4,16 @@
namespace ServiceStack.OrmLite.Dapper
{
- partial class SqlMapper
+ public static partial class SqlMapper
{
///
/// Parses a data reader to a sequence of data of the supplied type. Used for deserializing a reader without a connection, etc.
///
+ /// The type to parse from the .
+ /// The data reader to parse results from.
public static IEnumerable Parse(this IDataReader reader)
{
- if(reader.Read())
+ if (reader.Read())
{
var deser = GetDeserializer(typeof(T), reader, 0, -1, false);
do
@@ -24,6 +26,8 @@ public static IEnumerable Parse(this IDataReader reader)
///
/// Parses a data reader to a sequence of data of the supplied type (as object). Used for deserializing a reader without a connection, etc.
///
+ /// The data reader to parse results from.
+ /// The type to parse from the .
public static IEnumerable Parse(this IDataReader reader, Type type)
{
if (reader.Read())
@@ -39,6 +43,7 @@ public static IEnumerable Parse(this IDataReader reader, Type type)
///
/// Parses a data reader to a sequence of dynamic. Used for deserializing a reader without a connection, etc.
///
+ /// The data reader to parse results from.
public static IEnumerable Parse(this IDataReader reader)
{
if (reader.Read())
@@ -50,7 +55,7 @@ public static IEnumerable Parse(this IDataReader reader)
} while (reader.Read());
}
}
-
+
///
/// Gets the row parser for a specific row on a data reader. This allows for type switching every row based on, for example, a TypeId column.
/// You could return a collection of the base type but have each more specific.
@@ -71,11 +76,12 @@ public static IEnumerable Parse(this IDataReader reader)
/// Gets the row parser for a specific row on a data reader. This allows for type switching every row based on, for example, a TypeId column.
/// You could return a collection of the base type but have each more specific.
///
- /// The data reader to get the parser for the current row from
- /// The type to get the parser for
- /// The start column index of the object (default 0)
- /// The length of columns to read (default -1 = all fields following startIndex)
- /// Return null if we can't find the first column? (default false)
+ /// The type of results to return.
+ /// The data reader to get the parser for the current row from.
+ /// The type to get the parser for.
+ /// The start column index of the object (default: 0).
+ /// The length of columns to read (default: -1 = all fields following startIndex).
+ /// Return null if we can't find the first column? (default: false).
/// A parser for this specific object from this row.
///
/// var result = new List<BaseType>();
@@ -122,9 +128,9 @@ public static IEnumerable Parse(this IDataReader reader)
public static Func GetRowParser(this IDataReader reader, Type concreteType = null,
int startIndex = 0, int length = -1, bool returnNullIfFirstMissing = false)
{
- if (concreteType == null) concreteType = typeof(T);
+ concreteType = concreteType ?? typeof(T);
var func = GetDeserializer(concreteType, reader, startIndex, length, returnNullIfFirstMissing);
- if (concreteType.IsValueType)
+ if (concreteType.IsValueType())
{
return _ => (T)func(_);
}
diff --git a/src/ServiceStack.OrmLite/Dapper/SqlMapper.IDynamicParameters.cs b/src/ServiceStack.OrmLite/Dapper/SqlMapper.IDynamicParameters.cs
index 71dcbb71d..16b6de122 100644
--- a/src/ServiceStack.OrmLite/Dapper/SqlMapper.IDynamicParameters.cs
+++ b/src/ServiceStack.OrmLite/Dapper/SqlMapper.IDynamicParameters.cs
@@ -2,7 +2,7 @@
namespace ServiceStack.OrmLite.Dapper
{
- partial class SqlMapper
+ public static partial class SqlMapper
{
///
/// Implement this interface to pass an arbitrary db specific set of parameters to Dapper
diff --git a/src/ServiceStack.OrmLite/Dapper/SqlMapper.IMemberMap.cs b/src/ServiceStack.OrmLite/Dapper/SqlMapper.IMemberMap.cs
index 45618be7a..97c28975f 100644
--- a/src/ServiceStack.OrmLite/Dapper/SqlMapper.IMemberMap.cs
+++ b/src/ServiceStack.OrmLite/Dapper/SqlMapper.IMemberMap.cs
@@ -3,7 +3,7 @@
namespace ServiceStack.OrmLite.Dapper
{
- partial class SqlMapper
+ public static partial class SqlMapper
{
///
/// Implements this interface to provide custom member mapping
diff --git a/src/ServiceStack.OrmLite/Dapper/SqlMapper.IParameterCallbacks.cs b/src/ServiceStack.OrmLite/Dapper/SqlMapper.IParameterCallbacks.cs
index a43574485..25102298b 100644
--- a/src/ServiceStack.OrmLite/Dapper/SqlMapper.IParameterCallbacks.cs
+++ b/src/ServiceStack.OrmLite/Dapper/SqlMapper.IParameterCallbacks.cs
@@ -1,6 +1,6 @@
namespace ServiceStack.OrmLite.Dapper
{
- partial class SqlMapper
+ public static partial class SqlMapper
{
///
/// Extends IDynamicParameters with facilities for executing callbacks after commands have completed
diff --git a/src/ServiceStack.OrmLite/Dapper/SqlMapper.IParameterLookup.cs b/src/ServiceStack.OrmLite/Dapper/SqlMapper.IParameterLookup.cs
index 3c2c0fcb9..af7505265 100644
--- a/src/ServiceStack.OrmLite/Dapper/SqlMapper.IParameterLookup.cs
+++ b/src/ServiceStack.OrmLite/Dapper/SqlMapper.IParameterLookup.cs
@@ -1,6 +1,6 @@
namespace ServiceStack.OrmLite.Dapper
{
- partial class SqlMapper
+ public static partial class SqlMapper
{
///
/// Extends IDynamicParameters providing by-name lookup of parameter values
@@ -10,6 +10,7 @@ public interface IParameterLookup : IDynamicParameters
///
/// Get the value of the specified parameter (return null if not found)
///
+ /// The name of the parameter to get.
object this[string name] { get; }
}
}
diff --git a/src/ServiceStack.OrmLite/Dapper/SqlMapper.ITypeHandler.cs b/src/ServiceStack.OrmLite/Dapper/SqlMapper.ITypeHandler.cs
index 7d4d5dd9c..aabaf0bfc 100644
--- a/src/ServiceStack.OrmLite/Dapper/SqlMapper.ITypeHandler.cs
+++ b/src/ServiceStack.OrmLite/Dapper/SqlMapper.ITypeHandler.cs
@@ -3,7 +3,7 @@
namespace ServiceStack.OrmLite.Dapper
{
- partial class SqlMapper
+ public static partial class SqlMapper
{
///
/// Implement this interface to perform custom type-based parameter handling and value parsing
diff --git a/src/ServiceStack.OrmLite/Dapper/SqlMapper.ITypeMap.cs b/src/ServiceStack.OrmLite/Dapper/SqlMapper.ITypeMap.cs
index b1e46b98e..64e501cb7 100644
--- a/src/ServiceStack.OrmLite/Dapper/SqlMapper.ITypeMap.cs
+++ b/src/ServiceStack.OrmLite/Dapper/SqlMapper.ITypeMap.cs
@@ -3,7 +3,7 @@
namespace ServiceStack.OrmLite.Dapper
{
- partial class SqlMapper
+ public static partial class SqlMapper
{
///
/// Implement this interface to change default mapping of reader columns to type members
diff --git a/src/ServiceStack.OrmLite/Dapper/SqlMapper.Identity.cs b/src/ServiceStack.OrmLite/Dapper/SqlMapper.Identity.cs
index 684e4d978..e9dc31967 100644
--- a/src/ServiceStack.OrmLite/Dapper/SqlMapper.Identity.cs
+++ b/src/ServiceStack.OrmLite/Dapper/SqlMapper.Identity.cs
@@ -3,35 +3,30 @@
namespace ServiceStack.OrmLite.Dapper
{
- partial class SqlMapper
+ public static partial class SqlMapper
{
///
- /// Identity of a cached query in Dapper, used for extensibility
+ /// Identity of a cached query in Dapper, used for extensibility.
///
public class Identity : IEquatable
{
- internal Identity ForGrid(Type primaryType, int gridIndex)
- {
- return new Identity(sql, commandType, connectionString, primaryType, parametersType, null, gridIndex);
- }
+ internal Identity ForGrid(Type primaryType, int gridIndex) =>
+ new Identity(sql, commandType, connectionString, primaryType, parametersType, null, gridIndex);
+
+ internal Identity ForGrid(Type primaryType, Type[] otherTypes, int gridIndex) =>
+ new Identity(sql, commandType, connectionString, primaryType, parametersType, otherTypes, gridIndex);
- internal Identity ForGrid(Type primaryType, Type[] otherTypes, int gridIndex)
- {
- return new Identity(sql, commandType, connectionString, primaryType, parametersType, otherTypes, gridIndex);
- }
///
- /// Create an identity for use with DynamicParameters, internal use only
+ /// Create an identity for use with DynamicParameters, internal use only.
///
- ///
+ /// The parameters type to create an for.
///
- public Identity ForDynamicParameters(Type type)
- {
- return new Identity(sql, commandType, connectionString, this.type, type, null, -1);
- }
+ public Identity ForDynamicParameters(Type type) =>
+ new Identity(sql, commandType, connectionString, this.type, type, null, -1);
internal Identity(string sql, CommandType? commandType, IDbConnection connection, Type type, Type parametersType, Type[] otherTypes)
- : this(sql, commandType, connection.ConnectionString, type, parametersType, otherTypes, 0)
- { }
+ : this(sql, commandType, connection.ConnectionString, type, parametersType, otherTypes, 0) { /* base call */ }
+
private Identity(string sql, CommandType? commandType, string connectionString, Type type, Type parametersType, Type[] otherTypes, int gridIndex)
{
this.sql = sql;
@@ -43,79 +38,83 @@ private Identity(string sql, CommandType? commandType, string connectionString,
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) + commandType.GetHashCode();
+ hashCode = (hashCode * 23) + gridIndex.GetHashCode();
+ hashCode = (hashCode * 23) + (sql?.GetHashCode() ?? 0);
+ hashCode = (hashCode * 23) + (type?.GetHashCode() ?? 0);
if (otherTypes != null)
{
foreach (var t in otherTypes)
{
- hashCode = hashCode * 23 + (t?.GetHashCode() ?? 0);
+ hashCode = (hashCode * 23) + (t?.GetHashCode() ?? 0);
}
}
- hashCode = hashCode * 23 + (connectionString == null ? 0 : connectionStringComparer.GetHashCode(connectionString));
- hashCode = hashCode * 23 + (parametersType?.GetHashCode() ?? 0);
+ hashCode = (hashCode * 23) + (connectionString == null ? 0 : connectionStringComparer.GetHashCode(connectionString));
+ hashCode = (hashCode * 23) + (parametersType?.GetHashCode() ?? 0);
}
}
///
- ///
+ /// Whether this equals another.
///
- ///
- ///
- public override bool Equals(object obj)
- {
- return Equals(obj as Identity);
- }
+ /// The other to compare to.
+ public override bool Equals(object obj) => Equals(obj as Identity);
+
///
- /// The sql
+ /// The raw SQL command.
///
public readonly string sql;
+
///
- /// The command type
+ /// The SQL command type.
///
public readonly CommandType? commandType;
///
- ///
+ /// The hash code of this Identity.
+ ///
+ public readonly int hashCode;
+
+ ///
+ /// The grid index (position in the reader) of this Identity.
///
- public readonly int hashCode, gridIndex;
+ public readonly int gridIndex;
+
///
- ///
+ /// This of this Identity.
///
public readonly Type type;
+
///
- ///
+ /// The connection string for this Identity.
///
public readonly string connectionString;
+
///
- ///
+ /// The type of the parameters object for this Identity.
///
public readonly Type parametersType;
+
///
- ///
+ /// Gets the hash code for this identity.
///
///
- public override int GetHashCode()
- {
- return hashCode;
- }
+ public override int GetHashCode() => hashCode;
+
///
/// Compare 2 Identity objects
///
- ///
- ///
+ /// The other object to compare.
+ /// Whether the two are equal
public bool Equals(Identity other)
{
- return
- other != null &&
- gridIndex == other.gridIndex &&
- type == other.type &&
- sql == other.sql &&
- commandType == other.commandType &&
- connectionStringComparer.Equals(connectionString, other.connectionString) &&
- parametersType == other.parametersType;
+ return other != null
+ && gridIndex == other.gridIndex
+ && type == other.type
+ && sql == other.sql
+ && commandType == other.commandType
+ && connectionStringComparer.Equals(connectionString, other.connectionString)
+ && parametersType == other.parametersType;
}
}
}
diff --git a/src/ServiceStack.OrmLite/Dapper/SqlMapper.Link.cs b/src/ServiceStack.OrmLite/Dapper/SqlMapper.Link.cs
index a909fed61..9192aa3a4 100644
--- a/src/ServiceStack.OrmLite/Dapper/SqlMapper.Link.cs
+++ b/src/ServiceStack.OrmLite/Dapper/SqlMapper.Link.cs
@@ -2,13 +2,15 @@
namespace ServiceStack.OrmLite.Dapper
{
- partial class SqlMapper
+ public static partial class SqlMapper
{
///
/// This is a micro-cache; suitable when the number of terms is controllable (a few hundred, for example),
/// and strictly append-only; you cannot change existing values. All key matches are on **REFERENCE**
/// equality. The type is fully thread-safe.
///
+ /// The type to cache.
+ /// The value type of the cache.
internal class Link where TKey : class
{
public static bool TryGet(Link link, TKey key, out TValue value)
@@ -25,14 +27,14 @@ public static bool TryGet(Link link, TKey key, out TValue value)
value = default(TValue);
return false;
}
+
public static bool TryAdd(ref Link head, TKey key, ref TValue value)
{
bool tryAgain;
do
{
var snapshot = Interlocked.CompareExchange(ref head, null, null);
- TValue found;
- if (TryGet(snapshot, key, out found))
+ if (TryGet(snapshot, key, out TValue found))
{ // existing match; report the existing value instead
value = found;
return false;
@@ -43,12 +45,14 @@ public static bool TryAdd(ref Link head, TKey key, ref TValue valu
} while (tryAgain);
return true;
}
+
private Link(TKey key, TValue value, Link tail)
{
Key = key;
Value = value;
Tail = tail;
}
+
public TKey Key { get; }
public TValue Value { get; }
public Link Tail { get; }
diff --git a/src/ServiceStack.OrmLite/Dapper/SqlMapper.LiteralToken.cs b/src/ServiceStack.OrmLite/Dapper/SqlMapper.LiteralToken.cs
index 482b7cff4..fedd9dcde 100644
--- a/src/ServiceStack.OrmLite/Dapper/SqlMapper.LiteralToken.cs
+++ b/src/ServiceStack.OrmLite/Dapper/SqlMapper.LiteralToken.cs
@@ -2,7 +2,7 @@
namespace ServiceStack.OrmLite.Dapper
{
- partial class SqlMapper
+ public static partial class SqlMapper
{
///
/// Represents a placeholder for a value that should be replaced as a literal value in the resulting sql
diff --git a/src/ServiceStack.OrmLite/Dapper/SqlMapper.Settings.cs b/src/ServiceStack.OrmLite/Dapper/SqlMapper.Settings.cs
index 10dd749f0..0d61b7e06 100644
--- a/src/ServiceStack.OrmLite/Dapper/SqlMapper.Settings.cs
+++ b/src/ServiceStack.OrmLite/Dapper/SqlMapper.Settings.cs
@@ -1,12 +1,57 @@
-namespace ServiceStack.OrmLite.Dapper
+using System;
+using System.Data;
+
+namespace ServiceStack.OrmLite.Dapper
{
- partial class SqlMapper
+ public static partial class SqlMapper
{
///
/// Permits specifying certain SqlMapper values globally.
///
public static class Settings
{
+ // disable single result by default; prevents errors AFTER the select being detected properly
+ private const CommandBehavior DefaultAllowedCommandBehaviors = ~CommandBehavior.SingleResult;
+ internal static CommandBehavior AllowedCommandBehaviors { get; private set; } = DefaultAllowedCommandBehaviors;
+ private static void SetAllowedCommandBehaviors(CommandBehavior behavior, bool enabled)
+ {
+ if (enabled) AllowedCommandBehaviors |= behavior;
+ else AllowedCommandBehaviors &= ~behavior;
+ }
+ ///
+ /// Gets or sets whether Dapper should use the CommandBehavior.SingleResult optimization
+ ///
+ /// Note that a consequence of enabling this option is that errors that happen after the first select may not be reported
+ public static bool UseSingleResultOptimization
+ {
+ get { return (AllowedCommandBehaviors & CommandBehavior.SingleResult) != 0; }
+ set { SetAllowedCommandBehaviors(CommandBehavior.SingleResult, value); }
+ }
+ ///
+ /// Gets or sets whether Dapper should use the CommandBehavior.SingleRow optimization
+ ///
+ /// Note that on some DB providers this optimization can have adverse performance impact
+ public static bool UseSingleRowOptimization
+ {
+ get { return (AllowedCommandBehaviors & CommandBehavior.SingleRow) != 0; }
+ set { SetAllowedCommandBehaviors(CommandBehavior.SingleRow, value); }
+ }
+
+ internal static bool DisableCommandBehaviorOptimizations(CommandBehavior behavior, Exception ex)
+ {
+ if (AllowedCommandBehaviors == DefaultAllowedCommandBehaviors
+ && (behavior & (CommandBehavior.SingleResult | CommandBehavior.SingleRow)) != 0)
+ {
+ if (ex.Message.Contains(nameof(CommandBehavior.SingleResult))
+ || ex.Message.Contains(nameof(CommandBehavior.SingleRow)))
+ { // some providers just just allow these, so: try again without them and stop issuing them
+ SetAllowedCommandBehaviors(CommandBehavior.SingleResult | CommandBehavior.SingleRow, false);
+ return true;
+ }
+ }
+ return false;
+ }
+
static Settings()
{
SetDefaults();
@@ -31,7 +76,6 @@ public static void SetDefaults()
///
public static bool ApplyNullValues { get; set; }
-
///
/// Should list expansions be padded with null-valued parameters, to prevent query-plan saturation? For example,
/// an 'in @foo' expansion with 7, 8 or 9 values will be sent as a list of 10 values, with 3, 2 or 1 of them null.
diff --git a/src/ServiceStack.OrmLite/Dapper/SqlMapper.TypeDeserializerCache.cs b/src/ServiceStack.OrmLite/Dapper/SqlMapper.TypeDeserializerCache.cs
index fe7b47e7f..70285a54d 100644
--- a/src/ServiceStack.OrmLite/Dapper/SqlMapper.TypeDeserializerCache.cs
+++ b/src/ServiceStack.OrmLite/Dapper/SqlMapper.TypeDeserializerCache.cs
@@ -6,16 +6,16 @@
namespace ServiceStack.OrmLite.Dapper
{
- partial class SqlMapper
+ public static partial class SqlMapper
{
-
private class TypeDeserializerCache
{
private TypeDeserializerCache(Type type)
{
this.type = type;
}
- static readonly Hashtable byType = new Hashtable();
+
+ private static readonly Hashtable byType = new Hashtable();
private readonly Type type;
internal static void Purge(Type type)
{
@@ -24,6 +24,7 @@ internal static void Purge(Type type)
byType.Remove(type);
}
}
+
internal static void Purge()
{
lock (byType)
@@ -48,8 +49,10 @@ internal static void Purge()
}
return found.GetReader(reader, startBound, length, returnNullIfFirstMissing);
}
- private Dictionary> readers = new Dictionary>();
- struct DeserializerKey : IEquatable
+
+ private readonly Dictionary> readers = new Dictionary>();
+
+ private struct DeserializerKey : IEquatable
{
private readonly int startBound, length;
private readonly bool returnNullIfFirstMissing;
@@ -85,10 +88,8 @@ public DeserializerKey(int hashCode, int startBound, int length, bool returnNull
}
}
- public override int GetHashCode()
- {
- return hashCode;
- }
+ public override int GetHashCode() => hashCode;
+
public override string ToString()
{ // only used in the debugger
if (names != null)
@@ -108,24 +109,26 @@ public override string ToString()
}
return base.ToString();
}
+
public override bool Equals(object obj)
{
return obj is DeserializerKey && Equals((DeserializerKey)obj);
}
+
public bool Equals(DeserializerKey other)
{
- if (this.hashCode != other.hashCode
- || this.startBound != other.startBound
- || this.length != other.length
- || this.returnNullIfFirstMissing != other.returnNullIfFirstMissing)
+ if (hashCode != other.hashCode
+ || startBound != other.startBound
+ || length != other.length
+ || returnNullIfFirstMissing != other.returnNullIfFirstMissing)
{
return false; // clearly different
}
for (int i = 0; i < length; i++)
{
- if ((this.names?[i] ?? this.reader?.GetName(startBound + i)) != (other.names?[i] ?? other.reader?.GetName(startBound + i))
+ if ((names?[i] ?? reader?.GetName(startBound + i)) != (other.names?[i] ?? other.reader?.GetName(startBound + i))
||
- (this.types?[i] ?? this.reader?.GetFieldType(startBound + i)) != (other.types?[i] ?? other.reader?.GetFieldType(startBound + i))
+ (types?[i] ?? reader?.GetFieldType(startBound + i)) != (other.types?[i] ?? other.reader?.GetFieldType(startBound + i))
)
{
return false; // different column name or type
@@ -134,6 +137,7 @@ public bool Equals(DeserializerKey other)
return true;
}
}
+
private Func GetReader(IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing)
{
if (length < 0) length = reader.FieldCount - startBound;
@@ -155,6 +159,5 @@ public bool Equals(DeserializerKey other)
}
}
}
-
}
}
diff --git a/src/ServiceStack.OrmLite/Dapper/SqlMapper.TypeHandler.cs b/src/ServiceStack.OrmLite/Dapper/SqlMapper.TypeHandler.cs
index 9d54f4fd4..3f8d57af5 100644
--- a/src/ServiceStack.OrmLite/Dapper/SqlMapper.TypeHandler.cs
+++ b/src/ServiceStack.OrmLite/Dapper/SqlMapper.TypeHandler.cs
@@ -3,11 +3,12 @@
namespace ServiceStack.OrmLite.Dapper
{
- partial class SqlMapper
+ public static partial class SqlMapper
{
///
/// Base-class for simple type-handlers
///
+ /// This this handler is for.
public abstract class TypeHandler : ITypeHandler
{
///
@@ -41,19 +42,25 @@ object ITypeHandler.Parse(Type destinationType, object value)
return Parse(value);
}
}
+
///
/// Base-class for simple type-handlers that are based around strings
///
+ /// This this handler is for.
public abstract class StringTypeHandler : TypeHandler
{
///
/// Parse a string into the expected type (the string will never be null)
///
+ /// The string to parse.
protected abstract T Parse(string xml);
+
///
/// Format an instace into a string (the instance will never be null)
///
+ /// The string to format.
protected abstract string Format(T xml);
+
///
/// Assign the value of a parameter before a command executes
///
@@ -63,6 +70,7 @@ public override void SetValue(IDbDataParameter parameter, T value)
{
parameter.Value = value == null ? (object)DBNull.Value : Format(value);
}
+
///
/// Parse a database value back to a typed value
///
diff --git a/src/ServiceStack.OrmLite/Dapper/SqlMapper.TypeHandlerCache.cs b/src/ServiceStack.OrmLite/Dapper/SqlMapper.TypeHandlerCache.cs
index a99d83da1..2952b50e4 100644
--- a/src/ServiceStack.OrmLite/Dapper/SqlMapper.TypeHandlerCache.cs
+++ b/src/ServiceStack.OrmLite/Dapper/SqlMapper.TypeHandlerCache.cs
@@ -4,35 +4,33 @@
namespace ServiceStack.OrmLite.Dapper
{
- partial class SqlMapper
+ public static partial class SqlMapper
{
///
/// Not intended for direct usage
///
+ /// The type to have a cache for.
[Obsolete(ObsoleteInternalUsageOnly, false)]
-#if !COREFX
+#if !NETSTANDARD1_3
[Browsable(false)]
#endif
[EditorBrowsable(EditorBrowsableState.Never)]
public static class TypeHandlerCache
{
///
- /// Not intended for direct usage
+ /// Not intended for direct usage.
///
+ /// The object to parse.
[Obsolete(ObsoleteInternalUsageOnly, true)]
- public static T Parse(object value)
- {
- return (T)handler.Parse(typeof(T), value);
- }
+ public static T Parse(object value) => (T)handler.Parse(typeof(T), value);
///
- /// Not intended for direct usage
+ /// Not intended for direct usage.
///
+ /// The parameter to set a value for.
+ /// The value to set.
[Obsolete(ObsoleteInternalUsageOnly, true)]
- public static void SetValue(IDbDataParameter parameter, object value)
- {
- handler.SetValue(parameter, value);
- }
+ public static void SetValue(IDbDataParameter parameter, object value) => handler.SetValue(parameter, value);
internal static void SetHandler(ITypeHandler handler)
{
diff --git a/src/ServiceStack.OrmLite/Dapper/SqlMapper.cs b/src/ServiceStack.OrmLite/Dapper/SqlMapper.cs
index 2ede424d2..b2a61febe 100644
--- a/src/ServiceStack.OrmLite/Dapper/SqlMapper.cs
+++ b/src/ServiceStack.OrmLite/Dapper/SqlMapper.cs
@@ -1,4 +1,4 @@
-/*
+/*
License: http://www.apache.org/licenses/LICENSE-2.0
Home page: https://github.com/StackExchange/dapper-dot-net
*/
@@ -17,36 +17,38 @@
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml;
-//using System.Xml.Linq;
+using System.Xml.Linq;
-#if NETSTANDARD2_0
+#if NETSTANDARD1_3
using DataException = System.InvalidOperationException;
#endif
namespace ServiceStack.OrmLite.Dapper
{
-
///
/// Dapper, a light weight object mapper for ADO.NET
///
public static partial class SqlMapper
{
- static int GetColumnHash(IDataReader reader, int startBound = 0, int length = -1)
+ private class PropertyInfoByNameComparer : IComparer
+ {
+ public int Compare(PropertyInfo x, PropertyInfo y) => string.CompareOrdinal(x.Name, y.Name);
+ }
+ private static int GetColumnHash(IDataReader reader, int startBound = 0, int length = -1)
{
unchecked
{
int max = length < 0 ? reader.FieldCount : startBound + length;
int hash = (-37 * startBound) + max;
for (int i = startBound; i < max; i++)
- {
+ {
object tmp = reader.GetName(i);
- hash = -79 * ((hash * 31) + (tmp?.GetHashCode() ?? 0)) + (reader.GetFieldType(i)?.GetHashCode() ?? 0);
+ hash = (-79 * ((hash * 31) + (tmp?.GetHashCode() ?? 0))) + (reader.GetFieldType(i)?.GetHashCode() ?? 0);
}
return hash;
}
}
-
///
/// Called if the query cache is purged via PurgeQueryCache
///
@@ -57,7 +59,7 @@ private static void OnQueryCachePurged()
handler?.Invoke(null, EventArgs.Empty);
}
- static readonly System.Collections.Concurrent.ConcurrentDictionary _queryCache = new System.Collections.Concurrent.ConcurrentDictionary();
+ private static readonly System.Collections.Concurrent.ConcurrentDictionary _queryCache = new System.Collections.Concurrent.ConcurrentDictionary();
private static void SetQueryCache(Identity key, CacheInfo value)
{
if (Interlocked.Increment(ref collect) == COLLECT_PER_ITEMS)
@@ -75,8 +77,7 @@ private static void CollectCacheGarbage()
{
if (pair.Value.GetHitCount() <= COLLECT_HIT_COUNT_MIN)
{
- CacheInfo cache;
- _queryCache.TryRemove(pair.Key, out cache);
+ _queryCache.TryRemove(pair.Key, out CacheInfo cache);
}
}
}
@@ -114,15 +115,14 @@ private static void PurgeQueryCacheByType(Type type)
{
foreach (var entry in _queryCache)
{
- CacheInfo cache;
if (entry.Key.type == type)
- _queryCache.TryRemove(entry.Key, out cache);
+ _queryCache.TryRemove(entry.Key, out CacheInfo cache);
}
TypeDeserializerCache.Purge(type);
}
///
- /// Return a count of all the cached queries by dapper
+ /// Return a count of all the cached queries by Dapper
///
///
public static int GetCachedSQLCount()
@@ -131,15 +131,16 @@ public static int GetCachedSQLCount()
}
///
- /// Return a list of all the queries cached by dapper
+ /// Return a list of all the queries cached by Dapper
///
///
///
public static IEnumerable> GetCachedSQL(int ignoreHitCountAbove = int.MaxValue)
{
var data = _queryCache.Select(pair => Tuple.Create(pair.Key.connectionString, pair.Key.sql, pair.Value.GetHitCount()));
- if (ignoreHitCountAbove < int.MaxValue) data = data.Where(tuple => tuple.Item3 <= ignoreHitCountAbove);
- return data;
+ return (ignoreHitCountAbove < int.MaxValue)
+ ? data.Where(tuple => tuple.Item3 <= ignoreHitCountAbove)
+ : data;
}
///
@@ -151,8 +152,7 @@ public static int GetCachedSQLCount()
var counts = new Dictionary();
foreach (var key in _queryCache.Keys)
{
- int count;
- if (!counts.TryGetValue(key.hashCode, out count))
+ if (!counts.TryGetValue(key.hashCode, out int count))
{
counts.Add(key.hashCode, 1);
}
@@ -164,129 +164,138 @@ public static int GetCachedSQLCount()
return from pair in counts
where pair.Value > 1
select Tuple.Create(pair.Key, pair.Value);
-
}
-
- static Dictionary typeMap;
+ private static Dictionary typeMap;
static SqlMapper()
{
typeMap = new Dictionary
- {
- [typeof(byte)] = DbType.Byte,
- [typeof(sbyte)] = DbType.SByte,
- [typeof(short)] = DbType.Int16,
- [typeof(ushort)] = DbType.UInt16,
- [typeof(int)] = DbType.Int32,
- [typeof(uint)] = DbType.UInt32,
- [typeof(long)] = DbType.Int64,
- [typeof(ulong)] = DbType.UInt64,
- [typeof(float)] = DbType.Single,
- [typeof(double)] = DbType.Double,
- [typeof(decimal)] = DbType.Decimal,
- [typeof(bool)] = DbType.Boolean,
- [typeof(string)] = DbType.String,
- [typeof(char)] = DbType.StringFixedLength,
- [typeof(Guid)] = DbType.Guid,
- [typeof(DateTime)] = DbType.DateTime,
- [typeof(DateTimeOffset)] = DbType.DateTimeOffset,
- [typeof(TimeSpan)] = DbType.Time,
- [typeof(byte[])] = DbType.Binary,
- [typeof(byte?)] = DbType.Byte,
- [typeof(sbyte?)] = DbType.SByte,
- [typeof(short?)] = DbType.Int16,
- [typeof(ushort?)] = DbType.UInt16,
- [typeof(int?)] = DbType.Int32,
- [typeof(uint?)] = DbType.UInt32,
- [typeof(long?)] = DbType.Int64,
- [typeof(ulong?)] = DbType.UInt64,
- [typeof(float?)] = DbType.Single,
- [typeof(double?)] = DbType.Double,
- [typeof(decimal?)] = DbType.Decimal,
- [typeof(bool?)] = DbType.Boolean,
- [typeof(char?)] = DbType.StringFixedLength,
- [typeof(Guid?)] = DbType.Guid,
- [typeof(DateTime?)] = DbType.DateTime,
- [typeof(DateTimeOffset?)] = DbType.DateTimeOffset,
- [typeof(TimeSpan?)] = DbType.Time,
- [typeof(object)] = DbType.Object
- };
+ {
+ [typeof(byte)] = DbType.Byte,
+ [typeof(sbyte)] = DbType.SByte,
+ [typeof(short)] = DbType.Int16,
+ [typeof(ushort)] = DbType.UInt16,
+ [typeof(int)] = DbType.Int32,
+ [typeof(uint)] = DbType.UInt32,
+ [typeof(long)] = DbType.Int64,
+ [typeof(ulong)] = DbType.UInt64,
+ [typeof(float)] = DbType.Single,
+ [typeof(double)] = DbType.Double,
+ [typeof(decimal)] = DbType.Decimal,
+ [typeof(bool)] = DbType.Boolean,
+ [typeof(string)] = DbType.String,
+ [typeof(char)] = DbType.StringFixedLength,
+ [typeof(Guid)] = DbType.Guid,
+ [typeof(DateTime)] = DbType.DateTime,
+ [typeof(DateTimeOffset)] = DbType.DateTimeOffset,
+ [typeof(TimeSpan)] = DbType.Time,
+ [typeof(byte[])] = DbType.Binary,
+ [typeof(byte?)] = DbType.Byte,
+ [typeof(sbyte?)] = DbType.SByte,
+ [typeof(short?)] = DbType.Int16,
+ [typeof(ushort?)] = DbType.UInt16,
+ [typeof(int?)] = DbType.Int32,
+ [typeof(uint?)] = DbType.UInt32,
+ [typeof(long?)] = DbType.Int64,
+ [typeof(ulong?)] = DbType.UInt64,
+ [typeof(float?)] = DbType.Single,
+ [typeof(double?)] = DbType.Double,
+ [typeof(decimal?)] = DbType.Decimal,
+ [typeof(bool?)] = DbType.Boolean,
+ [typeof(char?)] = DbType.StringFixedLength,
+ [typeof(Guid?)] = DbType.Guid,
+ [typeof(DateTime?)] = DbType.DateTime,
+ [typeof(DateTimeOffset?)] = DbType.DateTimeOffset,
+ [typeof(TimeSpan?)] = DbType.Time,
+ [typeof(object)] = DbType.Object
+ };
ResetTypeHandlers(false);
}
///
- /// Clear the registered type handlers
+ /// Clear the registered type handlers.
///
- public static void ResetTypeHandlers()
- {
- ResetTypeHandlers(true);
- }
+ public static void ResetTypeHandlers() => ResetTypeHandlers(true);
+
private static void ResetTypeHandlers(bool clone)
{
typeHandlers = new Dictionary();
-#if !NETSTANDARD2_0
+#if !NETSTANDARD1_3
AddTypeHandlerImpl(typeof(DataTable), new DataTableHandler(), clone);
- try // see https://github.com/StackExchange/dapper-dot-net/issues/424
+#endif
+ try
{
AddSqlDataRecordsTypeHandler(clone);
}
- catch { }
-#endif
+ catch { /* https://github.com/StackExchange/dapper-dot-net/issues/424 */ }
AddTypeHandlerImpl(typeof(XmlDocument), new XmlDocumentHandler(), clone);
- //AddTypeHandlerImpl(typeof(XDocument), new XDocumentHandler(), clone);
- //AddTypeHandlerImpl(typeof(XElement), new XElementHandler(), clone);
-
- allowedCommandBehaviors = DefaultAllowedCommandBehaviors;
+ AddTypeHandlerImpl(typeof(XDocument), new XDocumentHandler(), clone);
+ AddTypeHandlerImpl(typeof(XElement), new XElementHandler(), clone);
}
-#if !NETSTANDARD2_0
+
[MethodImpl(MethodImplOptions.NoInlining)]
private static void AddSqlDataRecordsTypeHandler(bool clone)
{
AddTypeHandlerImpl(typeof(IEnumerable), new SqlDataRecordHandler(), clone);
}
-#endif
///
- /// Configure the specified type to be mapped to a given db-type
+ /// Configure the specified type to be mapped to a given db-type.
///
+ /// The type to map from.
+ /// The database type to map to.
public static void AddTypeMap(Type type, DbType dbType)
{
// use clone, mutate, replace to avoid threading issues
var snapshot = typeMap;
- DbType oldValue;
- if (snapshot.TryGetValue(type, out oldValue) && oldValue == dbType) return; // nothing to do
+ if (snapshot.TryGetValue(type, out DbType oldValue) && oldValue == dbType) return; // nothing to do
- var newCopy = new Dictionary(snapshot) { [type] = dbType };
- typeMap = newCopy;
+ typeMap = new Dictionary(snapshot) { [type] = dbType };
}
///
- /// Configure the specified type to be processed by a custom handler
+ /// Removes the specified type from the Type/DbType mapping table.
///
- public static void AddTypeHandler(Type type, ITypeHandler handler)
+ /// The type to remove from the current map.
+ public static void RemoveTypeMap(Type type)
{
- AddTypeHandlerImpl(type, handler, true);
- }
+ // use clone, mutate, replace to avoid threading issues
+ var snapshot = typeMap;
- internal static bool HasTypeHandler(Type type)
- {
- return typeHandlers.ContainsKey(type);
+ if (!snapshot.ContainsKey(type)) return; // nothing to do
+
+ var newCopy = new Dictionary(snapshot);
+ newCopy.Remove(type);
+
+ typeMap = newCopy;
}
///
- /// Configure the specified type to be processed by a custom handler
+ /// Configure the specified type to be processed by a custom handler.
+ ///
+ /// The type to handle.
+ /// The handler to process the .
+ public static void AddTypeHandler(Type type, ITypeHandler handler) => AddTypeHandlerImpl(type, handler, true);
+
+ internal static bool HasTypeHandler(Type type) => typeHandlers.ContainsKey(type);
+
+ ///
+ /// Configure the specified type to be processed by a custom handler.
///
+ /// The type to handle.
+ /// The handler to process the .
+ /// Whether to clone the current type handler map.
public static void AddTypeHandlerImpl(Type type, ITypeHandler handler, bool clone)
{
if (type == null) throw new ArgumentNullException(nameof(type));
Type secondary = null;
- if(type.IsValueType)
+ if (type.IsValueType())
{
var underlying = Nullable.GetUnderlyingType(type);
- if(underlying == null)
+ if (underlying == null)
{
secondary = typeof(Nullable<>).MakeGenericType(type); // the Nullable
// type is already the T
@@ -299,14 +308,13 @@ public static void AddTypeHandlerImpl(Type type, ITypeHandler handler, bool clon
}
var snapshot = typeHandlers;
- ITypeHandler oldValue;
- if (snapshot.TryGetValue(type, out oldValue) && handler == oldValue) return; // nothing to do
+ if (snapshot.TryGetValue(type, out ITypeHandler oldValue) && handler == oldValue) return; // nothing to do
var newCopy = clone ? new Dictionary(snapshot) : snapshot;
#pragma warning disable 618
typeof(TypeHandlerCache<>).MakeGenericType(type).GetMethod(nameof(TypeHandlerCache.SetHandler), BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, new object[] { handler });
- if(secondary != null)
+ if (secondary != null)
{
typeof(TypeHandlerCache<>).MakeGenericType(secondary).GetMethod(nameof(TypeHandlerCache.SetHandler), BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, new object[] { handler });
}
@@ -319,18 +327,17 @@ public static void AddTypeHandlerImpl(Type type, ITypeHandler handler, bool clon
else
{
newCopy[type] = handler;
- if(secondary != null) newCopy[secondary] = handler;
+ if (secondary != null) newCopy[secondary] = handler;
}
typeHandlers = newCopy;
}
///
- /// Configure the specified type to be processed by a custom handler
+ /// Configure the specified type to be processed by a custom handler.
///
- public static void AddTypeHandler(TypeHandler handler)
- {
- AddTypeHandlerImpl(typeof(T), handler, true);
- }
+ /// The type to handle.
+ /// The handler for the type .
+ public static void AddTypeHandler(TypeHandler handler) => AddTypeHandlerImpl(typeof(T), handler, true);
private static Dictionary typeHandlers;
@@ -339,10 +346,11 @@ public static void AddTypeHandler(TypeHandler handler)
private const string ObsoleteInternalUsageOnly = "This method is for internal use only";
///
- /// Get the DbType that maps to a given value
+ /// Get the DbType that maps to a given value.
///
+ /// The object to get a corresponding database type for.
[Obsolete(ObsoleteInternalUsageOnly, false)]
-#if !NETSTANDARD2_0
+#if !NETSTANDARD1_3
[Browsable(false)]
#endif
[EditorBrowsable(EditorBrowsableState.Never)]
@@ -350,30 +358,31 @@ public static DbType GetDbType(object value)
{
if (value == null || value is DBNull) return DbType.Object;
- ITypeHandler handler;
- return LookupDbType(value.GetType(), "n/a", false, out handler);
-
+ return LookupDbType(value.GetType(), "n/a", false, out ITypeHandler handler);
}
///
/// OBSOLETE: For internal usage only. Lookup the DbType and handler for a given Type and member
///
+ /// The type to lookup.
+ /// The name (for error messages).
+ /// Whether to demand a value (throw if missing).
+ /// The handler for .
[Obsolete(ObsoleteInternalUsageOnly, false)]
-#if !NETSTANDARD2_0
+#if !NETSTANDARD1_3
[Browsable(false)]
#endif
[EditorBrowsable(EditorBrowsableState.Never)]
public static DbType LookupDbType(Type type, string name, bool demand, out ITypeHandler handler)
{
- DbType dbType;
handler = null;
var nullUnderlyingType = Nullable.GetUnderlyingType(type);
if (nullUnderlyingType != null) type = nullUnderlyingType;
- if (type.IsEnum && !typeMap.ContainsKey(type))
+ if (type.IsEnum() && !typeMap.ContainsKey(type))
{
type = Enum.GetUnderlyingType(type);
}
- if (typeMap.TryGetValue(type, out dbType))
+ if (typeMap.TryGetValue(type, out DbType dbType))
{
return dbType;
}
@@ -390,7 +399,7 @@ public static DbType LookupDbType(Type type, string name, bool demand, out IType
return DynamicParameters.EnumerableMultiParameter;
}
-#if !NETSTANDARD2_0
+#if !NETSTANDARD1_3 && !NETSTANDARD2_0
switch (type.FullName)
{
case "Microsoft.SqlServer.Types.SqlGeography":
@@ -404,93 +413,103 @@ public static DbType LookupDbType(Type type, string name, bool demand, out IType
return DbType.Object;
}
#endif
- if(demand)
+ if (demand)
throw new NotSupportedException($"The member {name} of type {type.FullName} cannot be used as a parameter value");
return DbType.Object;
-
}
-
-
///
/// Obtains the data as a list; if it is *already* a list, the original object is returned without
/// any duplication; otherwise, ToList() is invoked.
///
- public static List AsList(this IEnumerable source)
- {
- return (source == null || source is List) ? (List)source : source.ToList();
- }
+ /// The type of element in the list.
+ /// The enumerable to return as a list.
+ public static List AsList(this IEnumerable source) =>
+ (source == null || source is List) ? (List)source : source.ToList();
///
- /// Execute parameterized SQL
+ /// Execute parameterized SQL.
///
- /// Number of rows affected
- public static int Execute(
- this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null
- )
+ /// The connection to query on.
+ /// The SQL to execute for this query.
+ /// The parameters to use for this query.
+ /// The transaction to use for this query.
+ /// Number of seconds before command execution timeout.
+ /// Is it a stored proc or a batch?
+ /// The number of rows affected.
+ public static int Execute(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.Buffered);
return ExecuteImpl(cnn, ref command);
}
+
///
- /// Execute parameterized SQL
+ /// Execute parameterized SQL.
///
- /// Number of rows affected
- public static int Execute(this IDbConnection cnn, CommandDefinition command)
- {
- return ExecuteImpl(cnn, ref command);
- }
-
+ /// The connection to execute on.
+ /// The command to execute on this connection.
+ /// The number of rows affected.
+ public static int Execute(this IDbConnection cnn, CommandDefinition command) => ExecuteImpl(cnn, ref command);
///
- /// Execute parameterized SQL that selects a single value
+ /// Execute parameterized SQL that selects a single value.
///
- /// The first cell selected
- public static object ExecuteScalar(
- this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null
- )
+ /// The connection to execute on.
+ /// The SQL to execute.
+ /// The parameters to use for this command.
+ /// The transaction to use for this command.
+ /// Number of seconds before command execution timeout.
+ /// Is it a stored proc or a batch?
+ /// The first cell selected as .
+ public static object ExecuteScalar(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.Buffered);
return ExecuteScalarImpl(cnn, ref command);
}
///
- /// Execute parameterized SQL that selects a single value
+ /// Execute parameterized SQL that selects a single value.
///
- /// The first cell selected
- public static T ExecuteScalar(
- this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null
- )
+ /// The type to return.
+ /// The connection to execute on.
+ /// The SQL to execute.
+ /// The parameters to use for this command.
+ /// The transaction to use for this command.
+ /// Number of seconds before command execution timeout.
+ /// Is it a stored proc or a batch?
+ /// The first cell returned, as .
+ public static T ExecuteScalar(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.Buffered);
return ExecuteScalarImpl(cnn, ref command);
}
///
- /// Execute parameterized SQL that selects a single value
+ /// Execute parameterized SQL that selects a single value.
///
- /// The first cell selected
- public static object ExecuteScalar(this IDbConnection cnn, CommandDefinition command)
- {
- return ExecuteScalarImpl(cnn, ref command);
- }
+ /// The connection to execute on.
+ /// The command to execute.
+ /// The first cell selected as .
+ public static object ExecuteScalar(this IDbConnection cnn, CommandDefinition command) =>
+ ExecuteScalarImpl(cnn, ref command);
///
- /// Execute parameterized SQL that selects a single value
+ /// Execute parameterized SQL that selects a single value.
///
- /// The first cell selected
- public static T ExecuteScalar(this IDbConnection cnn, CommandDefinition command)
- {
- return ExecuteScalarImpl(cnn, ref command);
- }
+ /// The type to return.
+ /// The connection to execute on.
+ /// The command to execute.
+ /// The first cell selected as .
+ public static T ExecuteScalar(this IDbConnection cnn, CommandDefinition command) =>
+ ExecuteScalarImpl(cnn, ref command);
private static IEnumerable GetMultiExec(object param)
{
- return (param is IEnumerable &&
- !(param is string ||
- param is IEnumerable> ||
- param is IDynamicParameters)
- ) ? (IEnumerable) param : null;
+ return (param is IEnumerable
+ && !(param is string
+ || param is IEnumerable>
+ || param is IDynamicParameters)
+ ) ? (IEnumerable)param : null;
}
private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition command)
@@ -501,13 +520,11 @@ private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition com
CacheInfo info = null;
if (multiExec != null)
{
-#if ASYNC
- if((command.Flags & CommandFlags.Pipelined) != 0)
+ if ((command.Flags & CommandFlags.Pipelined) != 0)
{
// this includes all the code for concurrent/overlapped query
return ExecuteMultiImplAsync(cnn, command, multiExec).Result;
}
-#endif
bool isFirst = true;
int total = 0;
bool wasClosed = cnn.State == ConnectionState.Closed;
@@ -536,7 +553,8 @@ private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition com
}
}
command.OnCompleted();
- } finally
+ }
+ finally
{
if (wasClosed) cnn.Close();
}
@@ -553,8 +571,14 @@ private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition com
}
///
- /// Execute parameterized SQL and return an
+ /// Execute parameterized SQL and return an .
///
+ /// The connection to execute on.
+ /// The SQL to execute.
+ /// The parameters to use for this command.
+ /// The transaction to use for this command.
+ /// Number of seconds before command execution timeout.
+ /// Is it a stored proc or a batch?
/// An that can be used to iterate over the results of the SQL query.
///
/// This is typically used when the results of a query are not processed by Dapper, for example, used to fill a
@@ -571,19 +595,18 @@ private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition com
/// ]]>
///
///
- public static IDataReader ExecuteReader(
- this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null
-)
+ public static IDataReader ExecuteReader(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.Buffered);
- IDbCommand dbcmd;
- var reader = ExecuteReaderImpl(cnn, ref command, CommandBehavior.Default, out dbcmd);
+ var reader = ExecuteReaderImpl(cnn, ref command, CommandBehavior.Default, out IDbCommand dbcmd);
return new WrappedReader(dbcmd, reader);
}
///
- /// Execute parameterized SQL and return an
+ /// Execute parameterized SQL and return an .
///
+ /// The connection to execute on.
+ /// The command to execute.
/// An that can be used to iterate over the results of the SQL query.
///
/// This is typically used when the results of a query are not processed by Dapper, for example, used to fill a
@@ -591,13 +614,16 @@ private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition com
///
public static IDataReader ExecuteReader(this IDbConnection cnn, CommandDefinition command)
{
- IDbCommand dbcmd;
- var reader = ExecuteReaderImpl(cnn, ref command, CommandBehavior.Default, out dbcmd);
+ var reader = ExecuteReaderImpl(cnn, ref command, CommandBehavior.Default, out IDbCommand dbcmd);
return new WrappedReader(dbcmd, reader);
}
+
///
- /// Execute parameterized SQL and return an
+ /// Execute parameterized SQL and return an .
///
+ /// The connection to execute on.
+ /// The command to execute.
+ /// The flags for this reader.
/// An that can be used to iterate over the results of the SQL query.
///
/// This is typically used when the results of a query are not processed by Dapper, for example, used to fill a
@@ -605,62 +631,92 @@ public static IDataReader ExecuteReader(this IDbConnection cnn, CommandDefinitio
///
public static IDataReader ExecuteReader(this IDbConnection cnn, CommandDefinition command, CommandBehavior commandBehavior)
{
- IDbCommand dbcmd;
- var reader = ExecuteReaderImpl(cnn, ref command, commandBehavior, out dbcmd);
+ var reader = ExecuteReaderImpl(cnn, ref command, commandBehavior, out IDbCommand dbcmd);
return new WrappedReader(dbcmd, reader);
}
///
- /// Return a sequence of dynamic objects with properties matching the columns
+ /// Return a sequence of dynamic objects with properties matching the columns.
///
+ /// The connection to query on.
+ /// The SQL to execute for the query.
+ /// The parameters to pass, if any.
+ /// The transaction to use, if any.
+ /// Whether to buffer the results in memory.
+ /// The command timeout (in seconds).
+ /// The type of command to execute.
/// Note: each row can be accessed via "dynamic", or by casting to an IDictionary<string,object>
- public static IEnumerable Query(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
- {
- return Query(cnn, sql, param as object, transaction, buffered, commandTimeout, commandType);
- }
+ public static IEnumerable Query(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null) =>
+ Query(cnn, sql, param as object, transaction, buffered, commandTimeout, commandType);
///
- /// Return a dynamic object with properties matching the columns
+ /// Return a dynamic object with properties matching the columns.
///
+ /// The connection to query on.
+ /// The SQL to execute for the query.
+ /// The parameters to pass, if any.
+ /// The transaction to use, if any.
+ /// The command timeout (in seconds).
+ /// The type of command to execute.
/// Note: the row can be accessed via "dynamic", or by casting to an IDictionary<string,object>
- public static dynamic QueryFirst(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
- {
- return QueryFirst(cnn, sql, param as object, transaction, commandTimeout, commandType);
- }
- ///
- /// Return a dynamic object with properties matching the columns
- ///
- /// Note: the row can be accessed via "dynamic", or by casting to an IDictionary<string,object>
- public static dynamic QueryFirstOrDefault(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
- {
- return QueryFirstOrDefault(cnn, sql, param as object, transaction, commandTimeout, commandType);
- }
+ public static dynamic QueryFirst(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null) =>
+ QueryFirst(cnn, sql, param as object, transaction, commandTimeout, commandType);
+
///
- /// Return a dynamic object with properties matching the columns
+ /// Return a dynamic object with properties matching the columns.
///
+ /// The connection to query on.
+ /// The SQL to execute for the query.
+ /// The parameters to pass, if any.
+ /// The transaction to use, if any.
+ /// The command timeout (in seconds).
+ /// The type of command to execute.
/// Note: the row can be accessed via "dynamic", or by casting to an IDictionary<string,object>
- public static dynamic QuerySingle(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
- {
- return QuerySingle(cnn, sql, param as object, transaction, commandTimeout, commandType);
- }
+ public static dynamic QueryFirstOrDefault(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null) =>
+ QueryFirstOrDefault(cnn, sql, param as object, transaction, commandTimeout, commandType);
+
///
- /// Return a dynamic object with properties matching the columns
+ /// Return a dynamic object with properties matching the columns.
///
+ /// The connection to query on.
+ /// The SQL to execute for the query.
+ /// The parameters to pass, if any.
+ /// The transaction to use, if any.
+ /// The command timeout (in seconds).
+ /// The type of command to execute.
/// Note: the row can be accessed via "dynamic", or by casting to an IDictionary<string,object>
- public static dynamic QuerySingleOrDefault(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
- {
- return QuerySingleOrDefault(cnn, sql, param as object, transaction, commandTimeout, commandType);
- }
+ public static dynamic QuerySingle(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null) =>
+ QuerySingle(cnn, sql, param as object, transaction, commandTimeout, commandType);
///
- /// Executes a query, returning the data typed as per T
+ /// Return a dynamic object with properties matching the columns.
///
- /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
+ /// The connection to query on.
+ /// The SQL to execute for the query.
+ /// The parameters to pass, if any.
+ /// The transaction to use, if any.
+ /// The command timeout (in seconds).
+ /// The type of command to execute.
+ /// Note: the row can be accessed via "dynamic", or by casting to an IDictionary<string,object>
+ public static dynamic QuerySingleOrDefault(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null) =>
+ QuerySingleOrDefault(cnn, sql, param as object, transaction, commandTimeout, commandType);
+
+ ///
+ /// Executes a query, returning the data typed as .
+ ///
+ /// The type of results to return.
+ /// The connection to query on.
+ /// The SQL to execute for the query.
+ /// The parameters to pass, if any.
+ /// The transaction to use, if any.
+ /// Whether to buffer results in memory.
+ /// The command timeout (in seconds).
+ /// The type of command to execute.
+ ///
+ /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
/// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).
///
- public static IEnumerable Query(
- this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null
- )
+ public static IEnumerable Query(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
{
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, buffered ? CommandFlags.Buffered : CommandFlags.None);
var data = QueryImpl(cnn, command, typeof(T));
@@ -668,134 +724,205 @@ public static dynamic QuerySingleOrDefault(this IDbConnection cnn, string sql, o
}
///
- /// Executes a single-row query, returning the data typed as per T
+ /// Executes a single-row query, returning the data typed as .
///
- /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
+ /// The type of result to return.
+ /// The connection to query on.
+ /// The SQL to execute for the query.
+ /// The parameters to pass, if any.
+ /// The transaction to use, if any.
+ /// The command timeout (in seconds).
+ /// The type of command to execute.
+ ///
+ /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
/// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).
///
- public static T QueryFirst(
- this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null
- )
+ public static T QueryFirst(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None);
return QueryRowImpl(cnn, Row.First, ref command, typeof(T));
}
+
///
- /// Executes a single-row query, returning the data typed as per T
+ /// Executes a single-row query, returning the data typed as .
///
- /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
+ /// The type of result to return.
+ /// The connection to query on.
+ /// The SQL to execute for the query.
+ /// The parameters to pass, if any.
+ /// The transaction to use, if any.
+ /// The command timeout (in seconds).
+ /// The type of command to execute.
+ ///
+ /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
/// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).
///
- public static T QueryFirstOrDefault(
- this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null
- )
+ public static T QueryFirstOrDefault(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None);
return QueryRowImpl(cnn, Row.FirstOrDefault, ref command, typeof(T));
}
+
///
- /// Executes a single-row query, returning the data typed as per T
+ /// Executes a single-row query, returning the data typed as .
///
- /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
+ /// The type of result to return.
+ /// The connection to query on.
+ /// The SQL to execute for the query.
+ /// The parameters to pass, if any.
+ /// The transaction to use, if any.
+ /// The command timeout (in seconds).
+ /// The type of command to execute.
+ ///
+ /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
/// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).
///
- public static T QuerySingle(
- this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null
- )
+ public static T QuerySingle(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None);
return QueryRowImpl(cnn, Row.Single, ref command, typeof(T));
}
+
///
- /// Executes a single-row query, returning the data typed as per T
+ /// Executes a single-row query, returning the data typed as .
///
- /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
+ /// The type of result to return.
+ /// The connection to query on.
+ /// The SQL to execute for the query.
+ /// The parameters to pass, if any.
+ /// The transaction to use, if any.
+ /// The command timeout (in seconds).
+ /// The type of command to execute.
+ ///
+ /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
/// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).
///
- public static T QuerySingleOrDefault(
- this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null
- )
+ public static T QuerySingleOrDefault(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None);
return QueryRowImpl(cnn, Row.SingleOrDefault, ref command, typeof(T));
}
///
- /// Executes a single-row query, returning the data typed as per the Type suggested
+ /// Executes a single-row query, returning the data typed as .
///
- /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
+ /// The connection to query on.
+ /// The type to return.
+ /// The SQL to execute for the query.
+ /// The parameters to pass, if any.
+ /// The transaction to use, if any.
+ /// Whether to buffer results in memory.
+ /// The command timeout (in seconds).
+ /// The type of command to execute.
+ /// is null.
+ ///
+ /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
/// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).
///
- public static IEnumerable Query(
- this IDbConnection cnn, Type type, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null
- )
+ public static IEnumerable Query(this IDbConnection cnn, Type type, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
{
if (type == null) throw new ArgumentNullException(nameof(type));
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, buffered ? CommandFlags.Buffered : CommandFlags.None);
var data = QueryImpl(cnn, command, type);
return command.Buffered ? data.ToList() : data;
}
+
///
- /// Executes a single-row query, returning the data typed as per the Type suggested
+ /// Executes a single-row query, returning the data typed as .
///
- /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
+ /// The connection to query on.
+ /// The type to return.
+ /// The SQL to execute for the query.
+ /// The parameters to pass, if any.
+ /// The transaction to use, if any.
+ /// The command timeout (in seconds).
+ /// The type of command to execute.
+ /// is null.
+ ///
+ /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
/// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).
///
- public static object QueryFirst(
- this IDbConnection cnn, Type type, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null
- )
+ public static object QueryFirst(this IDbConnection cnn, Type type, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
if (type == null) throw new ArgumentNullException(nameof(type));
- var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None);
+ var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None);
return QueryRowImpl(cnn, Row.First, ref command, type);
}
+
///
- /// Executes a single-row query, returning the data typed as per the Type suggested
+ /// Executes a single-row query, returning the data typed as .
///
- /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
+ /// The connection to query on.
+ /// The type to return.
+ /// The SQL to execute for the query.
+ /// The parameters to pass, if any.
+ /// The transaction to use, if any.
+ /// The command timeout (in seconds).
+ /// The type of command to execute.
+ /// is null.
+ ///
+ /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
/// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).
///
- public static object QueryFirstOrDefault(
- this IDbConnection cnn, Type type, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null
- )
+ public static object QueryFirstOrDefault(this IDbConnection cnn, Type type, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
if (type == null) throw new ArgumentNullException(nameof(type));
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None);
return QueryRowImpl(cnn, Row.FirstOrDefault, ref command, type);
}
+
///
- /// Executes a single-row query, returning the data typed as per the Type suggested
+ /// Executes a single-row query, returning the data typed as .
///
- /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
+ /// The connection to query on.
+ /// The type to return.
+ /// The SQL to execute for the query.
+ /// The parameters to pass, if any.
+ /// The transaction to use, if any.
+ /// The command timeout (in seconds).
+ /// The type of command to execute.
+ /// is null.
+ ///
+ /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
/// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).
///
- public static object QuerySingle(
- this IDbConnection cnn, Type type, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null
- )
+ public static object QuerySingle(this IDbConnection cnn, Type type, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
if (type == null) throw new ArgumentNullException(nameof(type));
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None);
return QueryRowImpl(cnn, Row.Single, ref command, type);
}
+
///
- /// Executes a single-row query, returning the data typed as per the Type suggested
+ /// Executes a single-row query, returning the data typed as .
///
- /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
+ /// The connection to query on.
+ /// The type to return.
+ /// The SQL to execute for the query.
+ /// The parameters to pass, if any.
+ /// The transaction to use, if any.
+ /// The command timeout (in seconds).
+ /// The type of command to execute.
+ /// is null.
+ ///
+ /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
/// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).
///
- public static object QuerySingleOrDefault(
- this IDbConnection cnn, Type type, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null
- )
+ public static object QuerySingleOrDefault(this IDbConnection cnn, Type type, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
if (type == null) throw new ArgumentNullException(nameof(type));
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None);
return QueryRowImpl(cnn, Row.SingleOrDefault, ref command, type);
}
+
///
- /// Executes a query, returning the data typed as per T
+ /// Executes a query, returning the data typed as .
///
- /// the dynamic param may seem a bit odd, but this works around a major usability issue in vs, if it is Object vs completion gets annoying. Eg type new [space] get new object
- /// A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
+ /// The type of results to return.
+ /// The connection to query on.
+ /// The command used to query on this connection.
+ ///
+ /// A sequence of data of ; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
/// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).
///
public static IEnumerable Query(this IDbConnection cnn, CommandDefinition command)
@@ -805,73 +932,84 @@ public static IEnumerable Query(this IDbConnection cnn, CommandDefinition
}
///
- /// Executes a query, returning the data typed as per T
+ /// Executes a query, returning the data typed as .
///
- /// the dynamic param may seem a bit odd, but this works around a major usability issue in vs, if it is Object vs completion gets annoying. Eg type new [space] get new object
- /// A single instance or null of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
+ /// The type of results to return.
+ /// The connection to query on.
+ /// The command used to query on this connection.
+ ///
+ /// A single instance or null of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
/// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).
///
- public static T QueryFirst(this IDbConnection cnn, CommandDefinition command)
- {
- return QueryRowImpl(cnn, Row.First, ref command, typeof(T));
- }
+ public static T QueryFirst(this IDbConnection cnn, CommandDefinition command) =>
+ QueryRowImpl(cnn, Row.First, ref command, typeof(T));
+
///
- /// Executes a query, returning the data typed as per T
+ /// Executes a query, returning the data typed as .
///
- /// the dynamic param may seem a bit odd, but this works around a major usability issue in vs, if it is Object vs completion gets annoying. Eg type new [space] get new object
- /// A single or null instance of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
+ /// The type of results to return.
+ /// The connection to query on.
+ /// The command used to query on this connection.
+ ///
+ /// A single or null instance of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
/// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).
///
- public static T QueryFirstOrDefault(this IDbConnection cnn, CommandDefinition command)
- {
- return QueryRowImpl(cnn, Row.FirstOrDefault, ref command, typeof(T));
- }
+ public static T QueryFirstOrDefault(this IDbConnection cnn, CommandDefinition command) =>
+ QueryRowImpl(cnn, Row.FirstOrDefault, ref command, typeof(T));
+
///
- /// Executes a query, returning the data typed as per T
+ /// Executes a query, returning the data typed as .
///
- /// the dynamic param may seem a bit odd, but this works around a major usability issue in vs, if it is Object vs completion gets annoying. Eg type new [space] get new object
- /// A single instance of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
+ /// The type of results to return.
+ /// The connection to query on.
+ /// The command used to query on this connection.
+ ///
+ /// A single instance of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
/// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).
///
- public static T QuerySingle(this IDbConnection cnn, CommandDefinition command)
- {
- return QueryRowImpl(cnn, Row.Single, ref command, typeof(T));
- }
+ public static T QuerySingle(this IDbConnection cnn, CommandDefinition command) =>
+ QueryRowImpl(cnn, Row.Single, ref command, typeof(T));
+
///
- /// Executes a query, returning the data typed as per T
+ /// Executes a query, returning the data typed as .
///
- /// the dynamic param may seem a bit odd, but this works around a major usability issue in vs, if it is Object vs completion gets annoying. Eg type new [space] get new object
- /// A single instance of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
+ /// The type of results to return.
+ /// The connection to query on.
+ /// The command used to query on this connection.
+ ///
+ /// A single instance of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is
/// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).
///
- public static T QuerySingleOrDefault(this IDbConnection cnn, CommandDefinition command)
- {
- return QueryRowImpl(cnn, Row.SingleOrDefault, ref command, typeof(T));
- }
-
+ public static T QuerySingleOrDefault(this IDbConnection cnn, CommandDefinition command) =>
+ QueryRowImpl(cnn, Row.SingleOrDefault, ref command, typeof(T));
///
- /// Execute a command that returns multiple result sets, and access each in turn
+ /// Execute a command that returns multiple result sets, and access each in turn.
///
- public static GridReader QueryMultiple(
- this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null
- )
+ /// The connection to query on.
+ /// The SQL to execute for this query.
+ /// The parameters to use for this query.
+ /// The transaction to use for this query.
+ /// Number of seconds before command execution timeout.
+ /// Is it a stored proc or a batch?
+ public static GridReader QueryMultiple(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.Buffered);
return QueryMultipleImpl(cnn, ref command);
}
+
///
- /// Execute a command that returns multiple result sets, and access each in turn
+ /// Execute a command that returns multiple result sets, and access each in turn.
///
- public static GridReader QueryMultiple(this IDbConnection cnn, CommandDefinition command)
- {
- return QueryMultipleImpl(cnn, ref command);
- }
+ /// The connection to query on.
+ /// The command to execute for this query.
+ public static GridReader QueryMultiple(this IDbConnection cnn, CommandDefinition command) =>
+ QueryMultipleImpl(cnn, ref command);
private static GridReader QueryMultipleImpl(this IDbConnection cnn, ref CommandDefinition command)
{
object param = command.Parameters;
- Identity identity = new Identity(command.CommandText, command.CommandType, cnn, typeof(GridReader), param?.GetType(), null);
+ var identity = new Identity(command.CommandText, command.CommandType, cnn, typeof(GridReader), param?.GetType(), null);
CacheInfo info = GetCacheInfo(identity, param, command.AddToCache);
IDbCommand cmd = null;
@@ -895,8 +1033,11 @@ private static GridReader QueryMultipleImpl(this IDbConnection cnn, ref CommandD
{
if (reader != null)
{
- if (!reader.IsClosed) try { cmd?.Cancel(); }
+ if (!reader.IsClosed)
+ {
+ try { cmd?.Cancel(); }
catch { /* don't spoil the existing exception */ }
+ }
reader.Dispose();
}
cmd?.Dispose();
@@ -904,6 +1045,7 @@ private static GridReader QueryMultipleImpl(this IDbConnection cnn, ref CommandD
throw;
}
}
+
private static IDataReader ExecuteReaderWithFlagsFallback(IDbCommand cmd, bool wasClosed, CommandBehavior behavior)
{
try
@@ -912,7 +1054,7 @@ private static IDataReader ExecuteReaderWithFlagsFallback(IDbCommand cmd, bool w
}
catch (ArgumentException ex)
{ // thanks, Sqlite!
- if (DisableCommandBehaviorOptimizations(behavior, ex))
+ if (Settings.DisableCommandBehaviorOptimizations(behavior, ex))
{
// we can retry; this time it will have different flags
return cmd.ExecuteReader(GetBehavior(wasClosed, behavior));
@@ -920,6 +1062,7 @@ private static IDataReader ExecuteReaderWithFlagsFallback(IDbCommand cmd, bool w
throw;
}
}
+
private static IEnumerable QueryImpl(this IDbConnection cnn, CommandDefinition command, Type effectiveType)
{
object param = command.Parameters;
@@ -947,7 +1090,7 @@ private static IEnumerable QueryImpl(this IDbConnection cnn, CommandDefini
if (reader.FieldCount == 0) //https://code.google.com/p/dapper-dot-net/issues/detail?id=57
yield break;
tuple = info.Deserializer = new DeserializerState(hash, GetDeserializer(effectiveType, reader, 0, -1, false));
- if(command.AddToCache) SetQueryCache(identity, info);
+ if (command.AddToCache) SetQueryCache(identity, info);
}
var func = tuple.Func;
@@ -955,13 +1098,16 @@ private static IEnumerable QueryImpl(this IDbConnection cnn, CommandDefini
while (reader.Read())
{
object val = func(reader);
- if (val == null || val is T) {
+ if (val == null || val is T)
+ {
yield return (T)val;
- } else {
+ }
+ else
+ {
yield return (T)Convert.ChangeType(val, convertToType, CultureInfo.InvariantCulture);
}
}
- while (reader.NextResult()) { }
+ while (reader.NextResult()) { /* ignore subsequent result sets */ }
// happy path; close the reader cleanly - no
// need for "Cancel" etc
reader.Dispose();
@@ -973,8 +1119,11 @@ private static IEnumerable QueryImpl(this IDbConnection cnn, CommandDefini
{
if (reader != null)
{
- if (!reader.IsClosed) try { cmd.Cancel(); }
+ if (!reader.IsClosed)
+ {
+ try { cmd.Cancel(); }
catch { /* don't spoil the existing exception */ }
+ }
reader.Dispose();
}
if (wasClosed) cnn.Close();
@@ -986,12 +1135,13 @@ private static IEnumerable QueryImpl(this IDbConnection cnn, CommandDefini
internal enum Row
{
First = 0,
- FirstOrDefault = 1, // &FirstOrDefault != 0: allow zero rows
+ FirstOrDefault = 1, // & FirstOrDefault != 0: allow zero rows
Single = 2, // & Single != 0: demand at least one row
SingleOrDefault = 3
}
- static readonly int[] ErrTwoRows = new int[2], ErrZeroRows = new int[0];
- static void ThrowMultipleRows(Row row)
+
+ private static readonly int[] ErrTwoRows = new int[2], ErrZeroRows = new int[0];
+ private static void ThrowMultipleRows(Row row)
{
switch (row)
{ // get the standard exception from the runtime
@@ -1000,7 +1150,8 @@ static void ThrowMultipleRows(Row row)
default: throw new InvalidOperationException();
}
}
- static void ThrowZeroRows(Row row)
+
+ private static void ThrowZeroRows(Row row)
{
switch (row)
{ // get the standard exception from the runtime
@@ -1009,6 +1160,7 @@ static void ThrowZeroRows(Row row)
default: throw new InvalidOperationException();
}
}
+
private static T QueryRowImpl(IDbConnection cnn, Row row, ref CommandDefinition command, Type effectiveType)
{
object param = command.Parameters;
@@ -1055,13 +1207,13 @@ private static T QueryRowImpl(IDbConnection cnn, Row row, ref CommandDefiniti
result = (T)Convert.ChangeType(val, convertToType, CultureInfo.InvariantCulture);
}
if ((row & Row.Single) != 0 && reader.Read()) ThrowMultipleRows(row);
- while (reader.Read()) { }
+ while (reader.Read()) { /* ignore subsequent rows */ }
}
else if ((row & Row.FirstOrDefault) == 0) // demanding a row, and don't have one
{
ThrowZeroRows(row);
}
- while (reader.NextResult()) { }
+ while (reader.NextResult()) { /* ignore subsequent result sets */ }
// happy path; close the reader cleanly - no
// need for "Cancel" etc
reader.Dispose();
@@ -1074,8 +1226,11 @@ private static T QueryRowImpl(IDbConnection cnn, Row row, ref CommandDefiniti
{
if (reader != null)
{
- if (!reader.IsClosed) try { cmd.Cancel(); }
+ if (!reader.IsClosed)
+ {
+ try { cmd.Cancel(); }
catch { /* don't spoil the existing exception */ }
+ }
reader.Dispose();
}
if (wasClosed) cnn.Close();
@@ -1084,180 +1239,164 @@ private static T QueryRowImpl(IDbConnection cnn, Row row, ref CommandDefiniti
}
///
- /// Maps a query to objects
+ /// Perform a multi-mapping query with 2 input types.
+ /// This returns a single type, combined from the raw types via .
///
- /// The first type in the record set
- /// The second type in the record set
- /// The return type
- ///
- ///
- ///
- ///
- ///
- ///
- /// The Field we should split and read the second object from (default: id)
- /// Number of seconds before command execution timeout
+ /// The first type in the recordset.
+ /// The second type in the recordset.
+ /// The combined type to return.
+ /// The connection to query on.
+ /// The SQL to execute for this query.
+ /// The function to map row types to the return type.
+ /// The parameters to use for this query.
+ /// The transaction to use for this query.
+ /// Whether to buffer the results in memory.
+ /// The field we should split and read the second object from (default: "Id").
+ /// Number of seconds before command execution timeout.
/// Is it a stored proc or a batch?
- ///
- public static IEnumerable Query(
- this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null
- )
- {
- return MultiMap(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType);
- }
-
- ///
- /// Maps a query to objects
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- /// The Field we should split and read the second object from (default: id)
- /// Number of seconds before command execution timeout
- ///
- ///
- public static IEnumerable Query(
- this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null
- )
- {
- return MultiMap(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType);
- }
-
- ///
- /// Perform a multi mapping query with 4 input parameters
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static IEnumerable Query(
- this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null
- )
- {
- return MultiMap(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType);
- }
-
- ///
- /// Perform a multi mapping query with 5 input parameters
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static IEnumerable Query(
- this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null
-)
- {
- return MultiMap(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType);
- }
-
- ///
- /// Perform a multi mapping query with 6 input parameters
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static IEnumerable Query(
- this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null
-)
- {
- return MultiMap(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType);
- }
-
-
- ///
- /// Perform a multi mapping query with 7 input parameters
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static IEnumerable Query(this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null)
- {
- return MultiMap(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType);
- }
-
- ///
- /// Perform a multi mapping query with arbitrary input parameters
- ///
- /// The return type
- ///
- ///
- /// array of types in the record set
- ///
- ///
- ///
- ///
- /// The Field we should split and read the second object from (default: id)
- /// Number of seconds before command execution timeout
+ /// An enumerable of .
+ public static IEnumerable Query(this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null) =>
+ MultiMap(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType);
+
+ ///
+ /// Perform a multi-mapping query with 3 input types.
+ /// This returns a single type, combined from the raw types via .
+ ///
+ /// The first type in the recordset.
+ /// The second type in the recordset.
+ /// The third type in the recordset.
+ /// The combined type to return.
+ /// The connection to query on.
+ /// The SQL to execute for this query.
+ /// The function to map row types to the return type.
+ /// The parameters to use for this query.
+ /// The transaction to use for this query.
+ /// Whether to buffer the results in memory.
+ /// The field we should split and read the second object from (default: "Id").
+ /// Number of seconds before command execution timeout.
/// Is it a stored proc or a batch?
- ///
+ /// An enumerable of .
+ public static IEnumerable Query(this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null) =>
+ MultiMap(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType);
+
+ ///
+ /// Perform a multi-mapping query with 4 input types.
+ /// This returns a single type, combined from the raw types via .
+ ///
+ /// The first type in the recordset.
+ /// The second type in the recordset.
+ /// The third type in the recordset.
+ /// The fourth type in the recordset.
+ /// The combined type to return.
+ /// The connection to query on.
+ /// The SQL to execute for this query.
+ /// The function to map row types to the return type.
+ /// The parameters to use for this query.
+ /// The transaction to use for this query.
+ /// Whether to buffer the results in memory.
+ /// The field we should split and read the second object from (default: "Id").
+ /// Number of seconds before command execution timeout.
+ /// Is it a stored proc or a batch?
+ /// An enumerable of .
+ public static IEnumerable Query(this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null) =>
+ MultiMap(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType);
+
+ ///
+ /// Perform a multi-mapping query with 5 input types.
+ /// This returns a single type, combined from the raw types via .
+ ///
+ /// The first type in the recordset.
+ /// The second type in the recordset.
+ /// The third type in the recordset.
+ /// The fourth type in the recordset.
+ /// The fifth type in the recordset.
+ /// The combined type to return.
+ /// The connection to query on.
+ /// The SQL to execute for this query.
+ /// The function to map row types to the return type.
+ /// The parameters to use for this query.
+ /// The transaction to use for this query.
+ /// Whether to buffer the results in memory.
+ /// The field we should split and read the second object from (default: "Id").
+ /// Number of seconds before command execution timeout.
+ /// Is it a stored proc or a batch?
+ /// An enumerable of .
+ public static IEnumerable Query(this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null) =>
+ MultiMap(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType);
+
+ ///
+ /// Perform a multi-mapping query with 6 input types.
+ /// This returns a single type, combined from the raw types via .
+ ///
+ /// The first type in the recordset.
+ /// The second type in the recordset.
+ /// The third type in the recordset.
+ /// The fourth type in the recordset.
+ /// The fifth type in the recordset.
+ /// The sixth type in the recordset.
+ /// The combined type to return.
+ /// The connection to query on.
+ /// The SQL to execute for this query.
+ /// The function to map row types to the return type.
+ /// The parameters to use for this query.
+ /// The transaction to use for this query.
+ /// Whether to buffer the results in memory.
+ /// The field we should split and read the second object from (default: "Id").
+ /// Number of seconds before command execution timeout.
+ /// Is it a stored proc or a batch?
+ /// An enumerable of .
+ public static IEnumerable Query(this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null) =>
+ MultiMap(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType);
+
+ ///
+ /// Perform a multi-mapping query with 7 input types.
+ /// This returns a single type, combined from the raw types via .
+ ///
+ /// The first type in the recordset.
+ /// The second type in the recordset.
+ /// The third type in the recordset.
+ /// The fourth type in the recordset.
+ /// The fifth type in the recordset.
+ /// The sixth type in the recordset.
+ /// The seventh type in the recordset.
+ /// The combined type to return.
+ /// The connection to query on.
+ /// The SQL to execute for this query.
+ /// The function to map row types to the return type.
+ /// The parameters to use for this query.
+ /// The transaction to use for this query.
+ /// Whether to buffer the results in memory.
+ /// The field we should split and read the second object from (default: "Id").
+ /// Number of seconds before command execution timeout.
+ /// Is it a stored proc or a batch?
+ /// An enumerable of .
+ public static IEnumerable Query(this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null) =>
+ MultiMap(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType);
+
+ ///
+ /// Perform a multi-mapping query with an arbitrary number of input types.
+ /// This returns a single type, combined from the raw types via .
+ ///
+ /// The combined type to return.
+ /// The connection to query on.
+ /// The SQL to execute for this query.
+ /// Array of types in the recordset.
+ /// The function to map row types to the return type.
+ /// The parameters to use for this query.
+ /// The transaction to use for this query.
+ /// Whether to buffer the results in memory.
+ /// The field we should split and read the second object from (default: "Id").
+ /// Number of seconds before command execution timeout.
+ /// Is it a stored proc or a batch?
+ /// An enumerable of .
public static IEnumerable Query(this IDbConnection cnn, string sql, Type[] types, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null)
{
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, buffered ? CommandFlags.Buffered : CommandFlags.None);
- var results = MultiMapImpl(cnn, command, types, map, splitOn, null, null, true);
+ var results = MultiMapImpl(cnn, command, types, map, splitOn, null, null, true);
return buffered ? results.ToList() : results;
}
- static IEnumerable MultiMap(
+ private static IEnumerable MultiMap(
this IDbConnection cnn, string sql, Delegate map, object param, IDbTransaction transaction, bool buffered, string splitOn, int? commandTimeout, CommandType? commandType)
{
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, buffered ? CommandFlags.Buffered : CommandFlags.None);
@@ -1265,7 +1404,7 @@ public static IEnumerable Query(this IDbConnection cnn, string
return buffered ? results.ToList() : results;
}
- static IEnumerable MultiMapImpl(this IDbConnection cnn, CommandDefinition command, Delegate map, string splitOn, IDataReader reader, Identity identity, bool finalize)
+ private static IEnumerable MultiMapImpl(this IDbConnection cnn, CommandDefinition command, Delegate map, string splitOn, IDataReader reader, Identity identity, bool finalize)
{
object param = command.Parameters;
identity = identity ?? new Identity(command.CommandText, command.CommandType, cnn, typeof(TFirst), param?.GetType(), new[] { typeof(TFirst), typeof(TSecond), typeof(TThird), typeof(TFourth), typeof(TFifth), typeof(TSixth), typeof(TSeventh) });
@@ -1274,7 +1413,7 @@ public static IEnumerable Query(this IDbConnection cnn, string
IDbCommand ownedCommand = null;
IDataReader ownedReader = null;
- bool wasClosed = cnn != null && cnn.State == ConnectionState.Closed;
+ bool wasClosed = cnn?.State == ConnectionState.Closed;
try
{
if (reader == null)
@@ -1284,16 +1423,16 @@ public static IEnumerable Query(this IDbConnection cnn, string
ownedReader = ExecuteReaderWithFlagsFallback(ownedCommand, wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult);
reader = ownedReader;
}
- DeserializerState deserializer = default(DeserializerState);
+ var deserializer = default(DeserializerState);
Func[] otherDeserializers;
int hash = GetColumnHash(reader);
if ((deserializer = cinfo.Deserializer).Func == null || (otherDeserializers = cinfo.OtherDeserializers) == null || hash != deserializer.Hash)
{
- var deserializers = GenerateDeserializers(new [] { typeof(TFirst), typeof(TSecond), typeof(TThird), typeof(TFourth), typeof(TFifth), typeof(TSixth), typeof(TSeventh) }, splitOn, reader);
+ var deserializers = GenerateDeserializers(new[] { typeof(TFirst), typeof(TSecond), typeof(TThird), typeof(TFourth), typeof(TFifth), typeof(TSixth), typeof(TSeventh) }, splitOn, reader);
deserializer = cinfo.Deserializer = new DeserializerState(hash, deserializers[0]);
otherDeserializers = cinfo.OtherDeserializers = deserializers.Skip(1).ToArray();
- if(command.AddToCache) SetQueryCache(identity, cinfo);
+ if (command.AddToCache) SetQueryCache(identity, cinfo);
}
Func mapIt = GenerateMapper(deserializer.Func, otherDeserializers, map);
@@ -1304,9 +1443,9 @@ public static IEnumerable Query(this IDbConnection cnn, string
{
yield return mapIt(reader);
}
- if(finalize)
+ if (finalize)
{
- while (reader.NextResult()) { }
+ while (reader.NextResult()) { /* ignore remaining result sets */ }
command.OnCompleted();
}
}
@@ -1324,27 +1463,13 @@ public static IEnumerable Query(this IDbConnection cnn, string
}
}
}
- const CommandBehavior DefaultAllowedCommandBehaviors = ~((CommandBehavior)0);
- static CommandBehavior allowedCommandBehaviors = DefaultAllowedCommandBehaviors;
- private static bool DisableCommandBehaviorOptimizations(CommandBehavior behavior, Exception ex)
- {
- if(allowedCommandBehaviors == DefaultAllowedCommandBehaviors
- && (behavior & (CommandBehavior.SingleResult | CommandBehavior.SingleRow)) != 0)
- {
- if (ex.Message.Contains(nameof(CommandBehavior.SingleResult))
- || ex.Message.Contains(nameof(CommandBehavior.SingleRow)))
- { // some providers just just allow these, so: try again without them and stop issuing them
- allowedCommandBehaviors = ~(CommandBehavior.SingleResult | CommandBehavior.SingleRow);
- return true;
- }
- }
- return false;
- }
+
private static CommandBehavior GetBehavior(bool close, CommandBehavior @default)
{
- return (close ? (@default | CommandBehavior.CloseConnection) : @default) & allowedCommandBehaviors;
+ return (close ? (@default | CommandBehavior.CloseConnection) : @default) & Settings.AllowedCommandBehaviors;
}
- static IEnumerable MultiMapImpl(this IDbConnection cnn, CommandDefinition command, Type[] types, Func map, string splitOn, IDataReader reader, Identity identity, bool finalize)
+
+ private static IEnumerable MultiMapImpl(this IDbConnection cnn, CommandDefinition command, Type[] types, Func map, string splitOn, IDataReader reader, Identity identity, bool finalize)
{
if (types.Length < 1)
{
@@ -1358,7 +1483,7 @@ static IEnumerable MultiMapImpl(this IDbConnection cnn, Comman
IDbCommand ownedCommand = null;
IDataReader ownedReader = null;
- bool wasClosed = cnn != null && cnn.State == ConnectionState.Closed;
+ bool wasClosed = cnn?.State == ConnectionState.Closed;
try
{
if (reader == null)
@@ -1390,7 +1515,7 @@ static IEnumerable MultiMapImpl(this IDbConnection cnn, Comman
}
if (finalize)
{
- while (reader.NextResult()) { }
+ while (reader.NextResult()) { /* ignore subsequent result sets */ }
command.OnCompleted();
}
}
@@ -1450,8 +1575,8 @@ static IEnumerable MultiMapImpl(this IDbConnection cnn, Comman
{
var deserializers = new List>();
var splits = splitOn.Split(',').Select(s => s.Trim()).ToArray();
- bool isMultiSplit = splits.Length > 1;
- if (types.First() == typeof(object))
+ bool isMultiSplit = splits.Length > 1;
+ if (types[0] == typeof(object))
{
// we go left to right for dynamic multi-mapping so that the madness of TestMultiMappingVariations
// is supported
@@ -1471,7 +1596,7 @@ static IEnumerable MultiMapImpl(this IDbConnection cnn, Comman
{
currentSplit = splits[++splitIdx];
}
- deserializers.Add((GetDeserializer(type, reader, currentPos, splitPoint - currentPos, !first)));
+ deserializers.Add(GetDeserializer(type, reader, currentPos, splitPoint - currentPos, !first));
currentPos = splitPoint;
first = false;
}
@@ -1486,7 +1611,7 @@ static IEnumerable MultiMapImpl(this IDbConnection cnn, Comman
for (var typeIdx = types.Length - 1; typeIdx >= 0; --typeIdx)
{
var type = types[typeIdx];
- if (type == typeof (DontMap))
+ if (type == typeof(DontMap))
{
continue;
}
@@ -1501,13 +1626,13 @@ static IEnumerable MultiMapImpl(this IDbConnection cnn, Comman
}
}
- deserializers.Add((GetDeserializer(type, reader, splitPoint, currentPos - splitPoint, typeIdx > 0)));
+ deserializers.Add(GetDeserializer(type, reader, splitPoint, currentPos - splitPoint, typeIdx > 0));
currentPos = splitPoint;
}
deserializers.Reverse();
-
}
+
return deserializers.ToArray();
}
@@ -1554,10 +1679,9 @@ private static int GetNextSplit(int startIdx, string splitOn, IDataReader reader
private static CacheInfo GetCacheInfo(Identity identity, object exampleParameters, bool addToCache)
{
- CacheInfo info;
- if (!TryGetQueryCache(identity, out info))
+ if (!TryGetQueryCache(identity, out CacheInfo info))
{
- if(GetMultiExec(exampleParameters) != null)
+ if (GetMultiExec(exampleParameters) != null)
{
throw new InvalidOperationException("An enumerable sequence of parameters (arrays, lists, etc) is not allowed in this context");
}
@@ -1567,7 +1691,7 @@ private static CacheInfo GetCacheInfo(Identity identity, object exampleParameter
Action reader;
if (exampleParameters is IDynamicParameters)
{
- reader = (cmd, obj) => { ((IDynamicParameters)obj).AddParameters(cmd, identity); };
+ reader = (cmd, obj) => ((IDynamicParameters)obj).AddParameters(cmd, identity);
}
else if (exampleParameters is IEnumerable>)
{
@@ -1582,7 +1706,7 @@ private static CacheInfo GetCacheInfo(Identity identity, object exampleParameter
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) =>
@@ -1593,14 +1717,14 @@ private static CacheInfo GetCacheInfo(Identity identity, object exampleParameter
}
info.ParamReader = reader;
}
- if(addToCache) SetQueryCache(identity, info);
+ if (addToCache) SetQueryCache(identity, info);
}
return info;
}
private static bool ShouldPassByPosition(string sql)
{
- return sql != null && sql.IndexOf('?') >= 0 && pseudoPositional.IsMatch(sql);
+ return sql?.IndexOf('?') >= 0 && pseudoPositional.IsMatch(sql);
}
private static void PassByPosition(IDbCommand cmd)
@@ -1609,7 +1733,7 @@ private static void PassByPosition(IDbCommand cmd)
Dictionary parameters = new Dictionary(StringComparer.Ordinal);
- foreach(IDbDataParameter param in cmd.Parameters)
+ foreach (IDbDataParameter param in cmd.Parameters)
{
if (!string.IsNullOrEmpty(param.ParameterName)) parameters[param.ParameterName] = param;
}
@@ -1618,14 +1742,13 @@ private static void PassByPosition(IDbCommand cmd)
cmd.CommandText = pseudoPositional.Replace(cmd.CommandText, match =>
{
string key = match.Groups[1].Value;
- IDbDataParameter param;
if (!consumed.Add(key))
{
throw new InvalidOperationException("When passing parameters by position, each parameter can only be referenced once");
}
- else if (parameters.TryGetValue(key, out param))
+ else if (parameters.TryGetValue(key, out IDbDataParameter param))
{
- if(firstMatch)
+ if (firstMatch)
{
firstMatch = false;
cmd.Parameters.Clear(); // only clear if we are pretty positive that we've found this pattern successfully
@@ -1646,19 +1769,16 @@ private static void PassByPosition(IDbCommand cmd)
private static Func GetDeserializer(Type type, IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing)
{
-
// dynamic is passed in as Object ... by c# design
- if (type == typeof(object)
- || type == typeof(DapperRow))
+ if (type == typeof(object) || type == typeof(DapperRow))
{
return GetDapperRowDeserializer(reader, startBound, length, returnNullIfFirstMissing);
}
Type underlyingType = null;
- if (!(typeMap.ContainsKey(type) || type.IsEnum || type.FullName == LinqBinary ||
- (type.IsValueType && (underlyingType = Nullable.GetUnderlyingType(type)) != null && underlyingType.IsEnum)))
+ if (!(typeMap.ContainsKey(type) || type.IsEnum() || type.FullName == LinqBinary
+ || (type.IsValueType() && (underlyingType = Nullable.GetUnderlyingType(type)) != null && underlyingType.IsEnum())))
{
- ITypeHandler handler;
- if (typeHandlers.TryGetValue(type, out handler))
+ if (typeHandlers.TryGetValue(type, out ITypeHandler handler))
{
return GetHandlerDeserializer(handler, type, startBound);
}
@@ -1666,18 +1786,17 @@ private static void PassByPosition(IDbCommand cmd)
}
return GetStructDeserializer(type, underlyingType ?? type, startBound);
}
+
private static Func GetHandlerDeserializer(ITypeHandler handler, Type type, int startBound)
{
return reader => handler.Parse(type, reader.GetValue(startBound));
}
-
private static Exception MultiMapException(IDataRecord reader)
{
bool hasFields = false;
- try {
- hasFields = reader != null && reader.FieldCount != 0;
- } catch { }
+ try { hasFields = reader != null && reader.FieldCount != 0; }
+ catch { /* don't throw when trying to throw */ }
if (hasFields)
return new ArgumentException("When using the multi-mapping APIs ensure you set the splitOn param if you have keys other than Id", "splitOn");
else
@@ -1746,11 +1865,10 @@ private static Exception MultiMapException(IDataRecord reader)
};
}
///
- /// Internal use only
+ /// Internal use only.
///
- ///
- ///
-#if !NETSTANDARD2_0
+ /// The object to convert to a character.
+#if !NETSTANDARD1_3
[Browsable(false)]
#endif
[EditorBrowsable(EditorBrowsableState.Never)]
@@ -1758,15 +1876,16 @@ private static Exception MultiMapException(IDataRecord reader)
public static char ReadChar(object value)
{
if (value == null || value is DBNull) throw new ArgumentNullException(nameof(value));
- string s = value as string;
+ var s = value as string;
if (s == null || s.Length != 1) throw new ArgumentException("A single-character was expected", nameof(value));
return s[0];
}
///
- /// Internal use only
+ /// Internal use only.
///
-#if !NETSTANDARD2_0
+ /// The object to convert to a character.
+#if !NETSTANDARD1_3
[Browsable(false)]
#endif
[EditorBrowsable(EditorBrowsableState.Never)]
@@ -1774,16 +1893,18 @@ public static char ReadChar(object value)
public static char? ReadNullableChar(object value)
{
if (value == null || value is DBNull) return null;
- string s = value as string;
+ var s = value as string;
if (s == null || s.Length != 1) throw new ArgumentException("A single-character was expected", nameof(value));
return s[0];
}
-
///
- /// Internal use only
+ /// Internal use only.
///
-#if !NETSTANDARD2_0
+ /// The parameter collection to search in.
+ /// The command for this fetch.
+ /// The name of the parameter to get.
+#if !NETSTANDARD1_3
[Browsable(false)]
#endif
[EditorBrowsable(EditorBrowsableState.Never)]
@@ -1806,7 +1927,7 @@ public static IDbDataParameter FindOrAddParameter(IDataParameterCollection param
internal static int GetListPaddingExtraCount(int count)
{
- switch(count)
+ switch (count)
{
case 0:
case 1:
@@ -1833,11 +1954,15 @@ internal static int GetListPaddingExtraCount(int count)
private static string GetInListRegex(string name, bool byPosition) => byPosition
? (@"(\?)" + Regex.Escape(name) + @"\?(?!\w)(\s+(?i)unknown(?-i))?")
- : (@"([?@:]" + Regex.Escape(name) + @")(?!\w)(\s+(?i)unknown(?-i))?");
+ : ("([?@:]" + Regex.Escape(name) + @")(?!\w)(\s+(?i)unknown(?-i))?");
+
///
- /// Internal use only
+ /// Internal use only.
///
-#if !NETSTANDARD2_0
+ /// The command to pack parameters for.
+ /// The name prefix for these parameters.
+ /// The parameter value can be an
+#if !NETSTANDARD1_3
[Browsable(false)]
#endif
[EditorBrowsable(EditorBrowsableState.Never)]
@@ -1874,18 +1999,17 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
{
if (++count == 1) // first item: fetch some type info
{
- if(item == null)
+ if (item == null)
{
throw new NotSupportedException("The first item in a list-expansion cannot be null");
}
if (!isDbString)
{
- ITypeHandler handler;
- dbType = LookupDbType(item.GetType(), "", true, out handler);
+ dbType = LookupDbType(item.GetType(), "", true, out ITypeHandler handler);
}
}
var nextName = namePrefix + count.ToString();
- if (isDbString && item as DbString != null)
+ if (isDbString && item is DbString)
{
var str = item as DbString;
str.AddParameter(command, nextName);
@@ -1922,7 +2046,7 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
count++;
var padParam = command.CreateParameter();
padParam.ParameterName = namePrefix + count.ToString();
- if(isString) padParam.Size = DbString.DefaultLength;
+ if (isString) padParam.Size = DbString.DefaultLength;
padParam.DbType = dbType;
padParam.Value = lastValue;
command.Parameters.Add(padParam);
@@ -1930,8 +2054,7 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
}
}
-
- if(viaSplit)
+ if (viaSplit)
{
// already done
}
@@ -1945,8 +2068,8 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
var variableName = match.Groups[1].Value;
if (match.Groups[2].Success)
{
- // looks like an optimize hint; leave it alone!
- return match.Value;
+ // looks like an optimize hint; leave it alone!
+ return match.Value;
}
else
{
@@ -1965,8 +2088,8 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
var variableName = match.Groups[1].Value;
if (match.Groups[2].Success)
{
- // looks like an optimize hint; expand it
- var suffix = match.Groups[2].Value;
+ // looks like an optimize hint; expand it
+ var suffix = match.Groups[2].Value;
var sb = GetStringBuilder().Append(variableName).Append(1).Append(suffix);
for (int i = 2; i <= count; i++)
@@ -1977,9 +2100,8 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
}
else
{
-
var sb = GetStringBuilder().Append('(').Append(variableName);
- if(!byPosition) sb.Append(1);
+ if (!byPosition) sb.Append(1);
for (int i = 2; i <= count; i++)
{
sb.Append(',').Append(variableName);
@@ -1996,27 +2118,31 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
private static bool TryStringSplit(ref IEnumerable list, int splitAt, string namePrefix, IDbCommand command, bool byPosition)
{
if (list == null || splitAt < 0) return false;
- if (list is IEnumerable) return TryStringSplit