Commit 071a3fd5 authored by Nick Craver's avatar Nick Craver

.editorconfig and formatting

parent 9e67f97f
# EditorConfig is awesome:http://EditorConfig.org
# top-most EditorConfig file
root = true
# Don't use tabs for indentation.
[*]
indent_style = space
# (Please don't specify an indent_size here; that has too many unintended consequences.)
# Code files
[*.{cs,csx,vb,vbx}]
indent_size = 4
insert_final_newline = true
charset = utf-8-bom
# Xml project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2
# Xml config files
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
indent_size = 2
# JSON files
[*.json]
indent_size = 2
# Dotnet code style settings:
[*.{cs,vb}]
# Sort using and Import directives with System.* appearing first
dotnet_sort_system_directives_first = true
# Avoid "this." and "Me." if not necessary
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_event = false:suggestion
# Use language keywords instead of framework type names for type references
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion
# Suggest more modern language features when available
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
# CSharp code style settings:
[*.cs]
# Prefer "var" everywhere
#csharp_style_var_for_built_in_types = true:suggestion
#csharp_style_var_when_type_is_apparent = false:suggestion
#csharp_style_var_elsewhere = true:suggestion
# Prefer method-like constructs to have a expression-body
csharp_style_expression_bodied_methods = true:none
csharp_style_expression_bodied_constructors = true:none
csharp_style_expression_bodied_operators = true:none
# Prefer property-like constructs to have an expression-body
csharp_style_expression_bodied_properties = true:none
csharp_style_expression_bodied_indexers = true:none
csharp_style_expression_bodied_accessors = true:none
# Suggest more modern language features when available
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
# Newline settings
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
\ No newline at end of file
...@@ -92,7 +92,7 @@ public static partial class SqlMapperExtensions ...@@ -92,7 +92,7 @@ public static partial class SqlMapperExtensions
private static async Task<IEnumerable<T>> GetAllAsyncImpl<T>(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string sql, Type type) where T : class private static async Task<IEnumerable<T>> GetAllAsyncImpl<T>(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string sql, Type type) where T : class
{ {
var result = await connection.QueryAsync(sql); var result = await connection.QueryAsync(sql).ConfigureAwait(false);
var list = new List<T>(); var list = new List<T>();
foreach (IDictionary<string, object> res in result) foreach (IDictionary<string, object> res in result)
{ {
...@@ -313,7 +313,7 @@ public partial interface ISqlAdapter ...@@ -313,7 +313,7 @@ public partial interface ISqlAdapter
/// <param name="keyProperties">The key columns in this table.</param> /// <param name="keyProperties">The key columns in this table.</param>
/// <param name="entityToInsert">The entity to insert.</param> /// <param name="entityToInsert">The entity to insert.</param>
/// <returns>The Id of the row created.</returns> /// <returns>The Id of the row created.</returns>
Task<int> InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, String tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert); Task<int> InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert);
} }
public partial class SqlServerAdapter public partial class SqlServerAdapter
...@@ -330,10 +330,10 @@ public partial class SqlServerAdapter ...@@ -330,10 +330,10 @@ public partial class SqlServerAdapter
/// <param name="keyProperties">The key columns in this table.</param> /// <param name="keyProperties">The key columns in this table.</param>
/// <param name="entityToInsert">The entity to insert.</param> /// <param name="entityToInsert">The entity to insert.</param>
/// <returns>The Id of the row created.</returns> /// <returns>The Id of the row created.</returns>
public async Task<int> InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, String tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert) public async Task<int> InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert)
{ {
var cmd = $"INSERT INTO {tableName} ({columnList}) values ({parameterList}); SELECT SCOPE_IDENTITY() id"; var cmd = $"INSERT INTO {tableName} ({columnList}) values ({parameterList}); SELECT SCOPE_IDENTITY() id";
var multi = await connection.QueryMultipleAsync(cmd, entityToInsert, transaction, commandTimeout); var multi = await connection.QueryMultipleAsync(cmd, entityToInsert, transaction, commandTimeout).ConfigureAwait(false);
var first = multi.Read().FirstOrDefault(); var first = multi.Read().FirstOrDefault();
if (first == null || first.id == null) return 0; if (first == null || first.id == null) return 0;
...@@ -485,7 +485,7 @@ public partial class SQLiteAdapter ...@@ -485,7 +485,7 @@ public partial class SQLiteAdapter
public async Task<int> InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert) public async Task<int> InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert)
{ {
var cmd = $"INSERT INTO {tableName} ({columnList}) VALUES ({parameterList}); SELECT last_insert_rowid() id"; var cmd = $"INSERT INTO {tableName} ({columnList}) VALUES ({parameterList}); SELECT last_insert_rowid() id";
var multi = await connection.QueryMultipleAsync(cmd, entityToInsert, transaction, commandTimeout); var multi = await connection.QueryMultipleAsync(cmd, entityToInsert, transaction, commandTimeout).ConfigureAwait(false);
var id = (int)multi.Read().First().id; var id = (int)multi.Read().First().id;
var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
...@@ -515,11 +515,11 @@ public partial class FbAdapter ...@@ -515,11 +515,11 @@ public partial class FbAdapter
public async Task<int> InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert) public async Task<int> InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert)
{ {
var cmd = $"insert into {tableName} ({columnList}) values ({parameterList})"; var cmd = $"insert into {tableName} ({columnList}) values ({parameterList})";
await connection.ExecuteAsync(cmd, entityToInsert, transaction, commandTimeout); await connection.ExecuteAsync(cmd, entityToInsert, transaction, commandTimeout).ConfigureAwait(false);
var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
var keyName = propertyInfos[0].Name; var keyName = propertyInfos[0].Name;
var r = await connection.QueryAsync($"SELECT FIRST 1 {keyName} ID FROM {tableName} ORDER BY {keyName} DESC", transaction: transaction, commandTimeout: commandTimeout); var r = await connection.QueryAsync($"SELECT FIRST 1 {keyName} ID FROM {tableName} ORDER BY {keyName} DESC", transaction: transaction, commandTimeout: commandTimeout).ConfigureAwait(false);
var id = r.First().ID; var id = r.First().ID;
if (id == null) return 0; if (id == null) return 0;
......
...@@ -114,7 +114,7 @@ private static List<PropertyInfo> KeyPropertiesCache(Type type) ...@@ -114,7 +114,7 @@ private static List<PropertyInfo> KeyPropertiesCache(Type type)
if (keyProperties.Count == 0) if (keyProperties.Count == 0)
{ {
var idProp = allProperties.FirstOrDefault(p => p.Name.ToLower() == "id"); var idProp = allProperties.Find(p => string.Equals(p.Name, "id", StringComparison.CurrentCultureIgnoreCase));
if (idProp != null && !idProp.GetCustomAttributes(true).Any(a => a is ExplicitKeyAttribute)) if (idProp != null && !idProp.GetCustomAttributes(true).Any(a => a is ExplicitKeyAttribute))
{ {
keyProperties.Add(idProp); keyProperties.Add(idProp);
...@@ -148,7 +148,7 @@ private static bool IsWriteable(PropertyInfo pi) ...@@ -148,7 +148,7 @@ private static bool IsWriteable(PropertyInfo pi)
private static PropertyInfo GetSingleKey<T>(string method) private static PropertyInfo GetSingleKey<T>(string method)
{ {
var type = typeof (T); var type = typeof(T);
var keys = KeyPropertiesCache(type); var keys = KeyPropertiesCache(type);
var explicitKeys = ExplicitKeyPropertiesCache(type); var explicitKeys = ExplicitKeyPropertiesCache(type);
var keyCount = keys.Count + explicitKeys.Count; var keyCount = keys.Count + explicitKeys.Count;
...@@ -564,17 +564,17 @@ public static T GetInterfaceProxy<T>() ...@@ -564,17 +564,17 @@ public static T GetInterfaceProxy<T>()
private static MethodInfo CreateIsDirtyProperty(TypeBuilder typeBuilder) private static MethodInfo CreateIsDirtyProperty(TypeBuilder typeBuilder)
{ {
var propType = typeof(bool); var propType = typeof(bool);
var field = typeBuilder.DefineField("_" + "IsDirty", propType, FieldAttributes.Private); var field = typeBuilder.DefineField("_" + nameof(IProxy.IsDirty), propType, FieldAttributes.Private);
var property = typeBuilder.DefineProperty("IsDirty", var property = typeBuilder.DefineProperty(nameof(IProxy.IsDirty),
System.Reflection.PropertyAttributes.None, System.Reflection.PropertyAttributes.None,
propType, propType,
new[] { propType }); new[] { propType });
const MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.NewSlot | MethodAttributes.SpecialName | const MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.NewSlot | MethodAttributes.SpecialName
MethodAttributes.Final | MethodAttributes.Virtual | MethodAttributes.HideBySig; | MethodAttributes.Final | MethodAttributes.Virtual | MethodAttributes.HideBySig;
// Define the "get" and "set" accessor methods // Define the "get" and "set" accessor methods
var currGetPropMthdBldr = typeBuilder.DefineMethod("get_" + "IsDirty", var currGetPropMthdBldr = typeBuilder.DefineMethod("get_" + nameof(IProxy.IsDirty),
getSetAttr, getSetAttr,
propType, propType,
Type.EmptyTypes); Type.EmptyTypes);
...@@ -582,7 +582,7 @@ private static MethodInfo CreateIsDirtyProperty(TypeBuilder typeBuilder) ...@@ -582,7 +582,7 @@ private static MethodInfo CreateIsDirtyProperty(TypeBuilder typeBuilder)
currGetIl.Emit(OpCodes.Ldarg_0); currGetIl.Emit(OpCodes.Ldarg_0);
currGetIl.Emit(OpCodes.Ldfld, field); currGetIl.Emit(OpCodes.Ldfld, field);
currGetIl.Emit(OpCodes.Ret); currGetIl.Emit(OpCodes.Ret);
var currSetPropMthdBldr = typeBuilder.DefineMethod("set_" + "IsDirty", var currSetPropMthdBldr = typeBuilder.DefineMethod("set_" + nameof(IProxy.IsDirty),
getSetAttr, getSetAttr,
null, null,
new[] { propType }); new[] { propType });
...@@ -594,8 +594,8 @@ private static MethodInfo CreateIsDirtyProperty(TypeBuilder typeBuilder) ...@@ -594,8 +594,8 @@ private static MethodInfo CreateIsDirtyProperty(TypeBuilder typeBuilder)
property.SetGetMethod(currGetPropMthdBldr); property.SetGetMethod(currGetPropMthdBldr);
property.SetSetMethod(currSetPropMthdBldr); property.SetSetMethod(currSetPropMthdBldr);
var getMethod = typeof(IProxy).GetMethod("get_" + "IsDirty"); var getMethod = typeof(IProxy).GetMethod("get_" + nameof(IProxy.IsDirty));
var setMethod = typeof(IProxy).GetMethod("set_" + "IsDirty"); var setMethod = typeof(IProxy).GetMethod("set_" + nameof(IProxy.IsDirty));
typeBuilder.DefineMethodOverride(currGetPropMthdBldr, getMethod); typeBuilder.DefineMethodOverride(currGetPropMthdBldr, getMethod);
typeBuilder.DefineMethodOverride(currSetPropMthdBldr, setMethod); typeBuilder.DefineMethodOverride(currSetPropMthdBldr, setMethod);
...@@ -841,7 +841,7 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com ...@@ -841,7 +841,7 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com
var r = connection.Query("select @@IDENTITY id", transaction: transaction, commandTimeout: commandTimeout).ToList(); var r = connection.Query("select @@IDENTITY id", transaction: transaction, commandTimeout: commandTimeout).ToList();
if (r[0].id == null) return 0; if (r[0].id == null) return 0;
var id = (int) r[0].id; var id = (int)r[0].id;
var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
if (propertyInfos.Length == 0) return id; if (propertyInfos.Length == 0) return id;
...@@ -1112,4 +1112,4 @@ public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) ...@@ -1112,4 +1112,4 @@ public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName)
{ {
sb.AppendFormat("{0} = @{1}", columnName, columnName); sb.AppendFormat("{0} = @{1}", columnName, columnName);
} }
} }
\ No newline at end of file
...@@ -88,7 +88,7 @@ public Task<int> UpdateAsync(TId id, dynamic data) ...@@ -88,7 +88,7 @@ public Task<int> UpdateAsync(TId id, dynamic data)
/// <param name="param">The parameters to use.</param> /// <param name="param">The parameters to use.</param>
/// <returns>The number of rows affected.</returns> /// <returns>The number of rows affected.</returns>
public Task<int> ExecuteAsync(string sql, dynamic param = null) => public Task<int> ExecuteAsync(string sql, dynamic param = null) =>
_connection.ExecuteAsync(sql, param as object, _transaction, this._commandTimeout); _connection.ExecuteAsync(sql, param as object, _transaction, _commandTimeout);
/// <summary> /// <summary>
/// Asynchronously queries the current database. /// Asynchronously queries the current database.
......
...@@ -166,10 +166,10 @@ public class Table<T> : Table<T, int> ...@@ -166,10 +166,10 @@ public class Table<T> : Table<T, int>
/// <param name="database">The database this table belongs in.</param> /// <param name="database">The database this table belongs in.</param>
/// <param name="likelyTableName">The name for this table.</param> /// <param name="likelyTableName">The name for this table.</param>
public Table(Database<TDatabase> database, string likelyTableName) public Table(Database<TDatabase> database, string likelyTableName)
: base(database, likelyTableName) : base(database, likelyTableName)
{ {
} }
} }
private DbConnection _connection; private DbConnection _connection;
private int _commandTimeout; private int _commandTimeout;
...@@ -238,7 +238,7 @@ public void RollbackTransaction() ...@@ -238,7 +238,7 @@ public void RollbackTransaction()
/// <returns>The function to create the <paramref name="tableType"/> table.</returns> /// <returns>The function to create the <paramref name="tableType"/> table.</returns>
protected Action<TDatabase> CreateTableConstructor(Type tableType) protected Action<TDatabase> CreateTableConstructor(Type tableType)
{ {
return CreateTableConstructor(new[] {tableType}); return CreateTableConstructor(new[] { tableType });
} }
/// <summary> /// <summary>
...@@ -315,7 +315,7 @@ private bool TableExists(string name) ...@@ -315,7 +315,7 @@ private bool TableExists(string name)
name = name.Replace("[", ""); name = name.Replace("[", "");
name = name.Replace("]", ""); name = name.Replace("]", "");
if(name.Contains(".")) if (name.Contains("."))
{ {
var parts = name.Split('.'); var parts = name.Split('.');
if (parts.Length == 2) if (parts.Length == 2)
......
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace Dapper namespace Dapper
{ {
public class SqlBuilder public class SqlBuilder
{ {
private readonly Dictionary<string, Clauses> _data = new Dictionary<string, Clauses>(); private readonly Dictionary<string, Clauses> _data = new Dictionary<string, Clauses>();
private int _seq; private int _seq;
private class Clause private class Clause
{ {
public string Sql { get; set; } public string Sql { get; set; }
public object Parameters { get; set; } public object Parameters { get; set; }
public bool IsInclusive { get; set; } public bool IsInclusive { get; set; }
}
private class Clauses : List<Clause>
{
private readonly string _joiner, _prefix, _postfix;
public Clauses(string joiner, string prefix = "", string postfix = "")
{
_joiner = joiner;
_prefix = prefix;
_postfix = postfix;
}
public string ResolveClauses(DynamicParameters p)
{
foreach (var item in this)
{
p.AddDynamicParams(item.Parameters);
}
return this.Any(a => a.IsInclusive)
? _prefix +
string.Join(_joiner,
this.Where(a => !a.IsInclusive)
.Select(c => c.Sql)
.Union(new[]
{
" ( " +
string.Join(" OR ", this.Where(a => a.IsInclusive).Select(c => c.Sql).ToArray()) +
" ) "
}).ToArray()) + _postfix
: _prefix + string.Join(_joiner, this.Select(c => c.Sql).ToArray()) + _postfix;
}
} }
private class Clauses : List<Clause> public class Template
{ {
private readonly string _joiner, _prefix, _postfix; private readonly string _sql;
private readonly SqlBuilder _builder;
public Clauses(string joiner, string prefix = "", string postfix = "") private readonly object _initParams;
{ private int _dataSeq = -1; // Unresolved
_joiner = joiner;
_prefix = prefix; public Template(SqlBuilder builder, string sql, dynamic parameters)
_postfix = postfix; {
} _initParams = parameters;
_sql = sql;
public string ResolveClauses(DynamicParameters p) _builder = builder;
{ }
foreach (var item in this)
{
p.AddDynamicParams(item.Parameters);
}
return this.Any(a => a.IsInclusive)
? _prefix +
string.Join(_joiner,
this.Where(a => !a.IsInclusive)
.Select(c => c.Sql)
.Union(new[]
{
" ( " +
string.Join(" OR ", this.Where(a => a.IsInclusive).Select(c => c.Sql).ToArray()) +
" ) "
}).ToArray()) + _postfix
: _prefix + string.Join(_joiner, this.Select(c => c.Sql).ToArray()) + _postfix;
}
}
public class Template
{
private readonly string _sql;
private readonly SqlBuilder _builder;
private readonly object _initParams;
private int _dataSeq = -1; // Unresolved
public Template(SqlBuilder builder, string sql, dynamic parameters)
{
_initParams = parameters;
_sql = sql;
_builder = builder;
}
private static readonly Regex _regex = new Regex(@"\/\*\*.+?\*\*\/", RegexOptions.Compiled | RegexOptions.Multiline); private static readonly Regex _regex = new Regex(@"\/\*\*.+?\*\*\/", RegexOptions.Compiled | RegexOptions.Multiline);
private void ResolveSql() private void ResolveSql()
{ {
if (_dataSeq != _builder._seq) if (_dataSeq != _builder._seq)
{ {
var p = new DynamicParameters(_initParams); var p = new DynamicParameters(_initParams);
rawSql = _sql; rawSql = _sql;
foreach (var pair in _builder._data) foreach (var pair in _builder._data)
{ {
rawSql = rawSql.Replace("/**" + pair.Key + "**/", pair.Value.ResolveClauses(p)); rawSql = rawSql.Replace("/**" + pair.Key + "**/", pair.Value.ResolveClauses(p));
} }
parameters = p; parameters = p;
// replace all that is left with empty // replace all that is left with empty
rawSql = _regex.Replace(rawSql, ""); rawSql = _regex.Replace(rawSql, "");
_dataSeq = _builder._seq; _dataSeq = _builder._seq;
} }
} }
private string rawSql; private string rawSql;
private object parameters; private object parameters;
public string RawSql public string RawSql
{ {
get { ResolveSql(); return rawSql; } get { ResolveSql(); return rawSql; }
} }
public object Parameters public object Parameters
{ {
get { ResolveSql(); return parameters; } get { ResolveSql(); return parameters; }
} }
} }
public Template AddTemplate(string sql, dynamic parameters = null) => public Template AddTemplate(string sql, dynamic parameters = null) =>
new Template(this, sql, parameters); new Template(this, sql, parameters);
protected SqlBuilder AddClause(string name, string sql, object parameters, string joiner, string prefix = "", string postfix = "", bool isInclusive = false) protected SqlBuilder AddClause(string name, string sql, object parameters, string joiner, string prefix = "", string postfix = "", bool isInclusive = false)
{ {
if (!_data.TryGetValue(name, out Clauses clauses)) if (!_data.TryGetValue(name, out Clauses clauses))
{ {
clauses = new Clauses(joiner, prefix, postfix); clauses = new Clauses(joiner, prefix, postfix);
_data[name] = clauses; _data[name] = clauses;
} }
clauses.Add(new Clause { Sql = sql, Parameters = parameters, IsInclusive = isInclusive }); clauses.Add(new Clause { Sql = sql, Parameters = parameters, IsInclusive = isInclusive });
_seq++; _seq++;
return this; return this;
} }
public SqlBuilder Intersect(string sql, dynamic parameters = null) => public SqlBuilder Intersect(string sql, dynamic parameters = null) =>
AddClause("intersect", sql, parameters, "\nINTERSECT\n ", "\n ", "\n", false); AddClause("intersect", sql, parameters, "\nINTERSECT\n ", "\n ", "\n", false);
public SqlBuilder InnerJoin(string sql, dynamic parameters = null) => public SqlBuilder InnerJoin(string sql, dynamic parameters = null) =>
AddClause("innerjoin", sql, parameters, "\nINNER JOIN ", "\nINNER JOIN ", "\n", false); AddClause("innerjoin", sql, parameters, "\nINNER JOIN ", "\nINNER JOIN ", "\n", false);
public SqlBuilder LeftJoin(string sql, dynamic parameters = null) => public SqlBuilder LeftJoin(string sql, dynamic parameters = null) =>
AddClause("leftjoin", sql, parameters, "\nLEFT JOIN ", "\nLEFT JOIN ", "\n", false); AddClause("leftjoin", sql, parameters, "\nLEFT JOIN ", "\nLEFT JOIN ", "\n", false);
public SqlBuilder RightJoin(string sql, dynamic parameters = null) => public SqlBuilder RightJoin(string sql, dynamic parameters = null) =>
AddClause("rightjoin", sql, parameters, "\nRIGHT JOIN ", "\nRIGHT JOIN ", "\n", false); AddClause("rightjoin", sql, parameters, "\nRIGHT JOIN ", "\nRIGHT JOIN ", "\n", false);
public SqlBuilder Where(string sql, dynamic parameters = null) => public SqlBuilder Where(string sql, dynamic parameters = null) =>
AddClause("where", sql, parameters, " AND ", "WHERE ", "\n", false); AddClause("where", sql, parameters, " AND ", "WHERE ", "\n", false);
public SqlBuilder OrWhere(string sql, dynamic parameters = null) => public SqlBuilder OrWhere(string sql, dynamic parameters = null) =>
AddClause("where", sql, parameters, " OR ", "WHERE ", "\n", true); AddClause("where", sql, parameters, " OR ", "WHERE ", "\n", true);
public SqlBuilder OrderBy(string sql, dynamic parameters = null) => public SqlBuilder OrderBy(string sql, dynamic parameters = null) =>
AddClause("orderby", sql, parameters, " , ", "ORDER BY ", "\n", false); AddClause("orderby", sql, parameters, " , ", "ORDER BY ", "\n", false);
public SqlBuilder Select(string sql, dynamic parameters = null) => public SqlBuilder Select(string sql, dynamic parameters = null) =>
AddClause("select", sql, parameters, " , ", "", "\n", false); AddClause("select", sql, parameters, " , ", "", "\n", false);
public SqlBuilder AddParameters(dynamic parameters) => public SqlBuilder AddParameters(dynamic parameters) =>
AddClause("--parameters", "", parameters, "", "", "", false); AddClause("--parameters", "", parameters, "", "", "", false);
public SqlBuilder Join(string sql, dynamic parameters = null) => public SqlBuilder Join(string sql, dynamic parameters = null) =>
AddClause("join", sql, parameters, "\nJOIN ", "\nJOIN ", "\n", false); AddClause("join", sql, parameters, "\nJOIN ", "\nJOIN ", "\n", false);
public SqlBuilder GroupBy(string sql, dynamic parameters = null) => public SqlBuilder GroupBy(string sql, dynamic parameters = null) =>
AddClause("groupby", sql, parameters, " , ", "\nGROUP BY ", "\n", false); AddClause("groupby", sql, parameters, " , ", "\nGROUP BY ", "\n", false);
public SqlBuilder Having(string sql, dynamic parameters = null) => public SqlBuilder Having(string sql, dynamic parameters = null) =>
AddClause("having", sql, parameters, "\nAND ", "HAVING ", "\n", false); AddClause("having", sql, parameters, "\nAND ", "HAVING ", "\n", false);
} }
} }
...@@ -40,7 +40,7 @@ public async Task InsertGetUpdateDeleteWithExplicitKeyAsync() ...@@ -40,7 +40,7 @@ public async Task InsertGetUpdateDeleteWithExplicitKeyAsync()
var originalyCount = connection.Query<int>("Select Count(*) From ObjectY").First(); var originalyCount = connection.Query<int>("Select Count(*) From ObjectY").First();
await connection.InsertAsync(o2).ConfigureAwait(false); await connection.InsertAsync(o2).ConfigureAwait(false);
var list2 = (await connection.QueryAsync<ObjectY>("select * from ObjectY").ConfigureAwait(false)).ToList(); var list2 = (await connection.QueryAsync<ObjectY>("select * from ObjectY").ConfigureAwait(false)).ToList();
Assert.Equal(list2.Count, originalyCount+1); Assert.Equal(list2.Count, originalyCount + 1);
o2 = await connection.GetAsync<ObjectY>(id).ConfigureAwait(false); o2 = await connection.GetAsync<ObjectY>(id).ConfigureAwait(false);
Assert.Equal(o2.ObjectYId, id); Assert.Equal(o2.ObjectYId, id);
o2.Name = "Bar"; o2.Name = "Bar";
...@@ -112,13 +112,13 @@ public async Task InsertGetUpdateAsync() ...@@ -112,13 +112,13 @@ public async Task InsertGetUpdateAsync()
Assert.True(await connection.UpdateAsync(notrackedUser).ConfigureAwait(false)); Assert.True(await connection.UpdateAsync(notrackedUser).ConfigureAwait(false));
Assert.Equal("Cecil", (await connection.GetAsync<User>(id).ConfigureAwait(false)).Name); Assert.Equal("Cecil", (await connection.GetAsync<User>(id).ConfigureAwait(false)).Name);
Assert.Equal((await connection.QueryAsync<User>("select * from Users").ConfigureAwait(false)).Count(), originalCount+1); Assert.Equal((await connection.QueryAsync<User>("select * from Users").ConfigureAwait(false)).Count(), originalCount + 1);
Assert.True(await connection.DeleteAsync(user).ConfigureAwait(false)); Assert.True(await connection.DeleteAsync(user).ConfigureAwait(false));
Assert.Equal((await connection.QueryAsync<User>("select * from Users").ConfigureAwait(false)).Count(), originalCount); Assert.Equal((await connection.QueryAsync<User>("select * from Users").ConfigureAwait(false)).Count(), originalCount);
Assert.False(await connection.UpdateAsync(notrackedUser).ConfigureAwait(false)); //returns false, user not found Assert.False(await connection.UpdateAsync(notrackedUser).ConfigureAwait(false)); //returns false, user not found
Assert.True(await connection.InsertAsync(new User {Name = "Adam", Age = 10}).ConfigureAwait(false) > originalCount + 1); Assert.True(await connection.InsertAsync(new User { Name = "Adam", Age = 10 }).ConfigureAwait(false) > originalCount + 1);
} }
} }
...@@ -348,4 +348,4 @@ public async Task DeleteAllAsync() ...@@ -348,4 +348,4 @@ public async Task DeleteAllAsync()
} }
} }
} }
} }
\ No newline at end of file
...@@ -180,7 +180,7 @@ public void GetAllWithExplicitKey() ...@@ -180,7 +180,7 @@ public void GetAllWithExplicitKey()
var objectXs = connection.GetAll<ObjectX>().ToList(); var objectXs = connection.GetAll<ObjectX>().ToList();
Assert.True(objectXs.Count > 0); Assert.True(objectXs.Count > 0);
Assert.Equal(1, objectXs.Count(x => x.ObjectXId== guid)); Assert.Equal(1, objectXs.Count(x => x.ObjectXId == guid));
} }
} }
......
...@@ -63,7 +63,7 @@ public class MySqlServerTestSuite : TestSuite ...@@ -63,7 +63,7 @@ public class MySqlServerTestSuite : TestSuite
{ {
private const string DbName = "DapperContribTests"; private const string DbName = "DapperContribTests";
public static string ConnectionString { get; private set; } = public static string ConnectionString { get; } =
IsAppVeyor IsAppVeyor
? "Server=localhost;Uid=root;Pwd=Password12!;" ? "Server=localhost;Uid=root;Pwd=Password12!;"
: "Server=localhost;Uid=test;Pwd=pass;"; : "Server=localhost;Uid=test;Pwd=pass;";
......
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using Dapper.Contrib.Extensions; using Dapper.Contrib.Extensions;
using System.Linq; using System.Linq;
...@@ -50,7 +50,7 @@ public dynamic QueryFirstOrDefaultDynamic() ...@@ -50,7 +50,7 @@ public dynamic QueryFirstOrDefaultDynamic()
Step(); Step();
return _connection.QueryFirstOrDefault("select * from Posts where Id = @Id", new { Id = i }).First(); return _connection.QueryFirstOrDefault("select * from Posts where Id = @Id", new { Id = i }).First();
} }
[Benchmark(Description = "Contrib Get<T>")] [Benchmark(Description = "Contrib Get<T>")]
public Post ContribGet() public Post ContribGet()
{ {
...@@ -58,4 +58,4 @@ public Post ContribGet() ...@@ -58,4 +58,4 @@ public Post ContribGet()
return _connection.Get<Post>(i); return _connection.Get<Post>(i);
} }
} }
} }
\ No newline at end of file
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using System; using System;
using System.Data; using System.Data;
using System.Data.SqlClient; using System.Data.SqlClient;
...@@ -86,8 +86,8 @@ public dynamic DataTableDynamic() ...@@ -86,8 +86,8 @@ public dynamic DataTableDynamic()
reader.Read(); reader.Read();
reader.GetValues(values); reader.GetValues(values);
_table.Rows.Add(values); _table.Rows.Add(values);
return _table.Rows[_table.Rows.Count-1]; return _table.Rows[_table.Rows.Count - 1];
} }
} }
} }
} }
\ No newline at end of file
...@@ -9,6 +9,6 @@ public EFContext(DbConnection connection, bool owned = false) : base(connection, ...@@ -9,6 +9,6 @@ public EFContext(DbConnection connection, bool owned = false) : base(connection,
{ {
} }
public DbSet<Post> Posts { get;set; } public DbSet<Post> Posts { get; set; }
} }
} }
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using System.Data.Linq; using System.Data.Linq;
...@@ -145,7 +145,7 @@ public async Task RunAsync(int iterations) ...@@ -145,7 +145,7 @@ public async Task RunAsync(int iterations)
var entityContext2 = new EFContext(connection); var entityContext2 = new EFContext(connection);
tests.Add(id => entityContext2.Database.SqlQuery<Post>("select * from Posts where Id = {0}", id).First(), "Entity Framework: SqlQuery"); tests.Add(id => entityContext2.Database.SqlQuery<Post>("select * from Posts where Id = {0}", id).First(), "Entity Framework: SqlQuery");
var entityContext3 = new EFContext(connection); var entityContext3 = new EFContext(connection);
tests.Add(id => entityContext3.Posts.AsNoTracking().First(p => p.Id == id), "Entity Framework: No Tracking"); tests.Add(id => entityContext3.Posts.AsNoTracking().First(p => p.Id == id), "Entity Framework: No Tracking");
}, "Entity Framework"); }, "Entity Framework");
...@@ -266,7 +266,8 @@ public async Task RunAsync(int iterations) ...@@ -266,7 +266,8 @@ public async Task RunAsync(int iterations)
}, "Belgrade Sql Client"); }, "Belgrade Sql Client");
//Susanoo //Susanoo
Try(() => { Try(() =>
{
var susanooDb = new DatabaseManager(connection); var susanooDb = new DatabaseManager(connection);
var susanooPreDefinedCommand = var susanooPreDefinedCommand =
...@@ -307,7 +308,8 @@ public async Task RunAsync(int iterations) ...@@ -307,7 +308,8 @@ public async Task RunAsync(int iterations)
}, "ServiceStack.OrmLite"); }, "ServiceStack.OrmLite");
// Hand Coded // Hand Coded
Try(() => { Try(() =>
{
var postCommand = new SqlCommand() var postCommand = new SqlCommand()
{ {
Connection = connection, Connection = connection,
...@@ -398,4 +400,4 @@ public async Task RunAsync(int iterations) ...@@ -398,4 +400,4 @@ public async Task RunAsync(int iterations)
} }
} }
} }
} }
\ No newline at end of file
...@@ -12,412 +12,412 @@ ...@@ -12,412 +12,412 @@
namespace Dapper.Tests.Performance.Linq2Sql namespace Dapper.Tests.Performance.Linq2Sql
{ {
using System.Data.Linq; using System.Data.Linq;
using System.Data.Linq.Mapping; using System.Data.Linq.Mapping;
using System.Data; using System.Data;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using System.Linq; using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.ComponentModel; using System.ComponentModel;
using System; using System;
[global::System.Data.Linq.Mapping.DatabaseAttribute(Name="tempdb")] [global::System.Data.Linq.Mapping.DatabaseAttribute(Name = "tempdb")]
public partial class DataClassesDataContext : System.Data.Linq.DataContext public partial class DataClassesDataContext : System.Data.Linq.DataContext
{ {
private static System.Data.Linq.Mapping.MappingSource mappingSource = new AttributeMappingSource(); private static System.Data.Linq.Mapping.MappingSource mappingSource = new AttributeMappingSource();
#region Extensibility Method Definitions #region Extensibility Method Definitions
partial void OnCreated(); partial void OnCreated();
partial void InsertPost(Post instance); partial void InsertPost(Post instance);
partial void UpdatePost(Post instance); partial void UpdatePost(Post instance);
partial void DeletePost(Post instance); partial void DeletePost(Post instance);
#endregion #endregion
public DataClassesDataContext(string connection) : public DataClassesDataContext(string connection) :
base(connection, mappingSource) base(connection, mappingSource)
{ {
OnCreated(); OnCreated();
} }
public DataClassesDataContext(System.Data.IDbConnection connection) : public DataClassesDataContext(System.Data.IDbConnection connection) :
base(connection, mappingSource) base(connection, mappingSource)
{ {
OnCreated(); OnCreated();
} }
public DataClassesDataContext(string connection, System.Data.Linq.Mapping.MappingSource mappingSource) : public DataClassesDataContext(string connection, System.Data.Linq.Mapping.MappingSource mappingSource) :
base(connection, mappingSource) base(connection, mappingSource)
{ {
OnCreated(); OnCreated();
} }
public DataClassesDataContext(System.Data.IDbConnection connection, System.Data.Linq.Mapping.MappingSource mappingSource) : public DataClassesDataContext(System.Data.IDbConnection connection, System.Data.Linq.Mapping.MappingSource mappingSource) :
base(connection, mappingSource) base(connection, mappingSource)
{ {
OnCreated(); OnCreated();
} }
public System.Data.Linq.Table<Post> Posts public System.Data.Linq.Table<Post> Posts
{ {
get get
{ {
return this.GetTable<Post>(); return this.GetTable<Post>();
} }
} }
} }
[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.Posts")] [global::System.Data.Linq.Mapping.TableAttribute(Name = "dbo.Posts")]
public partial class Post : INotifyPropertyChanging, INotifyPropertyChanged public partial class Post : INotifyPropertyChanging, INotifyPropertyChanged
{ {
private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty); private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
private int _Id; private int _Id;
private string _Text; private string _Text;
private System.DateTime _CreationDate; private System.DateTime _CreationDate;
private System.DateTime _LastChangeDate; private System.DateTime _LastChangeDate;
private System.Nullable<int> _Counter1; private System.Nullable<int> _Counter1;
private System.Nullable<int> _Counter2; private System.Nullable<int> _Counter2;
private System.Nullable<int> _Counter3; private System.Nullable<int> _Counter3;
private System.Nullable<int> _Counter4; private System.Nullable<int> _Counter4;
private System.Nullable<int> _Counter5; private System.Nullable<int> _Counter5;
private System.Nullable<int> _Counter6; private System.Nullable<int> _Counter6;
private System.Nullable<int> _Counter7; private System.Nullable<int> _Counter7;
private System.Nullable<int> _Counter8; private System.Nullable<int> _Counter8;
private System.Nullable<int> _Counter9; private System.Nullable<int> _Counter9;
#region Extensibility Method Definitions #region Extensibility Method Definitions
partial void OnLoaded(); partial void OnLoaded();
partial void OnValidate(System.Data.Linq.ChangeAction action); partial void OnValidate(System.Data.Linq.ChangeAction action);
partial void OnCreated(); partial void OnCreated();
partial void OnIdChanging(int value); partial void OnIdChanging(int value);
partial void OnIdChanged(); partial void OnIdChanged();
partial void OnTextChanging(string value); partial void OnTextChanging(string value);
partial void OnTextChanged(); partial void OnTextChanged();
partial void OnCreationDateChanging(System.DateTime value); partial void OnCreationDateChanging(System.DateTime value);
partial void OnCreationDateChanged(); partial void OnCreationDateChanged();
partial void OnLastChangeDateChanging(System.DateTime value); partial void OnLastChangeDateChanging(System.DateTime value);
partial void OnLastChangeDateChanged(); partial void OnLastChangeDateChanged();
partial void OnCounter1Changing(System.Nullable<int> value); partial void OnCounter1Changing(System.Nullable<int> value);
partial void OnCounter1Changed(); partial void OnCounter1Changed();
partial void OnCounter2Changing(System.Nullable<int> value); partial void OnCounter2Changing(System.Nullable<int> value);
partial void OnCounter2Changed(); partial void OnCounter2Changed();
partial void OnCounter3Changing(System.Nullable<int> value); partial void OnCounter3Changing(System.Nullable<int> value);
partial void OnCounter3Changed(); partial void OnCounter3Changed();
partial void OnCounter4Changing(System.Nullable<int> value); partial void OnCounter4Changing(System.Nullable<int> value);
partial void OnCounter4Changed(); partial void OnCounter4Changed();
partial void OnCounter5Changing(System.Nullable<int> value); partial void OnCounter5Changing(System.Nullable<int> value);
partial void OnCounter5Changed(); partial void OnCounter5Changed();
partial void OnCounter6Changing(System.Nullable<int> value); partial void OnCounter6Changing(System.Nullable<int> value);
partial void OnCounter6Changed(); partial void OnCounter6Changed();
partial void OnCounter7Changing(System.Nullable<int> value); partial void OnCounter7Changing(System.Nullable<int> value);
partial void OnCounter7Changed(); partial void OnCounter7Changed();
partial void OnCounter8Changing(System.Nullable<int> value); partial void OnCounter8Changing(System.Nullable<int> value);
partial void OnCounter8Changed(); partial void OnCounter8Changed();
partial void OnCounter9Changing(System.Nullable<int> value); partial void OnCounter9Changing(System.Nullable<int> value);
partial void OnCounter9Changed(); partial void OnCounter9Changed();
#endregion #endregion
public Post() public Post()
{ {
OnCreated(); OnCreated();
} }
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Id", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)] [global::System.Data.Linq.Mapping.ColumnAttribute(Storage = "_Id", AutoSync = AutoSync.OnInsert, DbType = "Int NOT NULL IDENTITY", IsPrimaryKey = true, IsDbGenerated = true)]
public int Id public int Id
{ {
get get
{ {
return this._Id; return this._Id;
} }
set set
{ {
if ((this._Id != value)) if ((this._Id != value))
{ {
this.OnIdChanging(value); this.OnIdChanging(value);
this.SendPropertyChanging(); this.SendPropertyChanging();
this._Id = value; this._Id = value;
this.SendPropertyChanged("Id"); this.SendPropertyChanged("Id");
this.OnIdChanged(); this.OnIdChanged();
} }
} }
} }
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Text", DbType="VarChar(MAX) NOT NULL", CanBeNull=false)] [global::System.Data.Linq.Mapping.ColumnAttribute(Storage = "_Text", DbType = "VarChar(MAX) NOT NULL", CanBeNull = false)]
public string Text public string Text
{ {
get get
{ {
return this._Text; return this._Text;
} }
set set
{ {
if ((this._Text != value)) if ((this._Text != value))
{ {
this.OnTextChanging(value); this.OnTextChanging(value);
this.SendPropertyChanging(); this.SendPropertyChanging();
this._Text = value; this._Text = value;
this.SendPropertyChanged("Text"); this.SendPropertyChanged("Text");
this.OnTextChanged(); this.OnTextChanged();
} }
} }
} }
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_CreationDate", DbType="DateTime NOT NULL")] [global::System.Data.Linq.Mapping.ColumnAttribute(Storage = "_CreationDate", DbType = "DateTime NOT NULL")]
public System.DateTime CreationDate public System.DateTime CreationDate
{ {
get get
{ {
return this._CreationDate; return this._CreationDate;
} }
set set
{ {
if ((this._CreationDate != value)) if ((this._CreationDate != value))
{ {
this.OnCreationDateChanging(value); this.OnCreationDateChanging(value);
this.SendPropertyChanging(); this.SendPropertyChanging();
this._CreationDate = value; this._CreationDate = value;
this.SendPropertyChanged("CreationDate"); this.SendPropertyChanged("CreationDate");
this.OnCreationDateChanged(); this.OnCreationDateChanged();
} }
} }
} }
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_LastChangeDate", DbType="DateTime NOT NULL")] [global::System.Data.Linq.Mapping.ColumnAttribute(Storage = "_LastChangeDate", DbType = "DateTime NOT NULL")]
public System.DateTime LastChangeDate public System.DateTime LastChangeDate
{ {
get get
{ {
return this._LastChangeDate; return this._LastChangeDate;
} }
set set
{ {
if ((this._LastChangeDate != value)) if ((this._LastChangeDate != value))
{ {
this.OnLastChangeDateChanging(value); this.OnLastChangeDateChanging(value);
this.SendPropertyChanging(); this.SendPropertyChanging();
this._LastChangeDate = value; this._LastChangeDate = value;
this.SendPropertyChanged("LastChangeDate"); this.SendPropertyChanged("LastChangeDate");
this.OnLastChangeDateChanged(); this.OnLastChangeDateChanged();
} }
} }
} }
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Counter1", DbType="Int")] [global::System.Data.Linq.Mapping.ColumnAttribute(Storage = "_Counter1", DbType = "Int")]
public System.Nullable<int> Counter1 public System.Nullable<int> Counter1
{ {
get get
{ {
return this._Counter1; return this._Counter1;
} }
set set
{ {
if ((this._Counter1 != value)) if ((this._Counter1 != value))
{ {
this.OnCounter1Changing(value); this.OnCounter1Changing(value);
this.SendPropertyChanging(); this.SendPropertyChanging();
this._Counter1 = value; this._Counter1 = value;
this.SendPropertyChanged("Counter1"); this.SendPropertyChanged("Counter1");
this.OnCounter1Changed(); this.OnCounter1Changed();
} }
} }
} }
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Counter2", DbType="Int")] [global::System.Data.Linq.Mapping.ColumnAttribute(Storage = "_Counter2", DbType = "Int")]
public System.Nullable<int> Counter2 public System.Nullable<int> Counter2
{ {
get get
{ {
return this._Counter2; return this._Counter2;
} }
set set
{ {
if ((this._Counter2 != value)) if ((this._Counter2 != value))
{ {
this.OnCounter2Changing(value); this.OnCounter2Changing(value);
this.SendPropertyChanging(); this.SendPropertyChanging();
this._Counter2 = value; this._Counter2 = value;
this.SendPropertyChanged("Counter2"); this.SendPropertyChanged("Counter2");
this.OnCounter2Changed(); this.OnCounter2Changed();
} }
} }
} }
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Counter3", DbType="Int")] [global::System.Data.Linq.Mapping.ColumnAttribute(Storage = "_Counter3", DbType = "Int")]
public System.Nullable<int> Counter3 public System.Nullable<int> Counter3
{ {
get get
{ {
return this._Counter3; return this._Counter3;
} }
set set
{ {
if ((this._Counter3 != value)) if ((this._Counter3 != value))
{ {
this.OnCounter3Changing(value); this.OnCounter3Changing(value);
this.SendPropertyChanging(); this.SendPropertyChanging();
this._Counter3 = value; this._Counter3 = value;
this.SendPropertyChanged("Counter3"); this.SendPropertyChanged("Counter3");
this.OnCounter3Changed(); this.OnCounter3Changed();
} }
} }
} }
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Counter4", DbType="Int")] [global::System.Data.Linq.Mapping.ColumnAttribute(Storage = "_Counter4", DbType = "Int")]
public System.Nullable<int> Counter4 public System.Nullable<int> Counter4
{ {
get get
{ {
return this._Counter4; return this._Counter4;
} }
set set
{ {
if ((this._Counter4 != value)) if ((this._Counter4 != value))
{ {
this.OnCounter4Changing(value); this.OnCounter4Changing(value);
this.SendPropertyChanging(); this.SendPropertyChanging();
this._Counter4 = value; this._Counter4 = value;
this.SendPropertyChanged("Counter4"); this.SendPropertyChanged("Counter4");
this.OnCounter4Changed(); this.OnCounter4Changed();
} }
} }
} }
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Counter5", DbType="Int")] [global::System.Data.Linq.Mapping.ColumnAttribute(Storage = "_Counter5", DbType = "Int")]
public System.Nullable<int> Counter5 public System.Nullable<int> Counter5
{ {
get get
{ {
return this._Counter5; return this._Counter5;
} }
set set
{ {
if ((this._Counter5 != value)) if ((this._Counter5 != value))
{ {
this.OnCounter5Changing(value); this.OnCounter5Changing(value);
this.SendPropertyChanging(); this.SendPropertyChanging();
this._Counter5 = value; this._Counter5 = value;
this.SendPropertyChanged("Counter5"); this.SendPropertyChanged("Counter5");
this.OnCounter5Changed(); this.OnCounter5Changed();
} }
} }
} }
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Counter6", DbType="Int")] [global::System.Data.Linq.Mapping.ColumnAttribute(Storage = "_Counter6", DbType = "Int")]
public System.Nullable<int> Counter6 public System.Nullable<int> Counter6
{ {
get get
{ {
return this._Counter6; return this._Counter6;
} }
set set
{ {
if ((this._Counter6 != value)) if ((this._Counter6 != value))
{ {
this.OnCounter6Changing(value); this.OnCounter6Changing(value);
this.SendPropertyChanging(); this.SendPropertyChanging();
this._Counter6 = value; this._Counter6 = value;
this.SendPropertyChanged("Counter6"); this.SendPropertyChanged("Counter6");
this.OnCounter6Changed(); this.OnCounter6Changed();
} }
} }
} }
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Counter7", DbType="Int")] [global::System.Data.Linq.Mapping.ColumnAttribute(Storage = "_Counter7", DbType = "Int")]
public System.Nullable<int> Counter7 public System.Nullable<int> Counter7
{ {
get get
{ {
return this._Counter7; return this._Counter7;
} }
set set
{ {
if ((this._Counter7 != value)) if ((this._Counter7 != value))
{ {
this.OnCounter7Changing(value); this.OnCounter7Changing(value);
this.SendPropertyChanging(); this.SendPropertyChanging();
this._Counter7 = value; this._Counter7 = value;
this.SendPropertyChanged("Counter7"); this.SendPropertyChanged("Counter7");
this.OnCounter7Changed(); this.OnCounter7Changed();
} }
} }
} }
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Counter8", DbType="Int")] [global::System.Data.Linq.Mapping.ColumnAttribute(Storage = "_Counter8", DbType = "Int")]
public System.Nullable<int> Counter8 public System.Nullable<int> Counter8
{ {
get get
{ {
return this._Counter8; return this._Counter8;
} }
set set
{ {
if ((this._Counter8 != value)) if ((this._Counter8 != value))
{ {
this.OnCounter8Changing(value); this.OnCounter8Changing(value);
this.SendPropertyChanging(); this.SendPropertyChanging();
this._Counter8 = value; this._Counter8 = value;
this.SendPropertyChanged("Counter8"); this.SendPropertyChanged("Counter8");
this.OnCounter8Changed(); this.OnCounter8Changed();
} }
} }
} }
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Counter9", DbType="Int")] [global::System.Data.Linq.Mapping.ColumnAttribute(Storage = "_Counter9", DbType = "Int")]
public System.Nullable<int> Counter9 public System.Nullable<int> Counter9
{ {
get get
{ {
return this._Counter9; return this._Counter9;
} }
set set
{ {
if ((this._Counter9 != value)) if ((this._Counter9 != value))
{ {
this.OnCounter9Changing(value); this.OnCounter9Changing(value);
this.SendPropertyChanging(); this.SendPropertyChanging();
this._Counter9 = value; this._Counter9 = value;
this.SendPropertyChanged("Counter9"); this.SendPropertyChanged("Counter9");
this.OnCounter9Changed(); this.OnCounter9Changed();
} }
} }
} }
public event PropertyChangingEventHandler PropertyChanging; public event PropertyChangingEventHandler PropertyChanging;
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
protected virtual void SendPropertyChanging() protected virtual void SendPropertyChanging()
{ {
if ((this.PropertyChanging != null)) if ((this.PropertyChanging != null))
{ {
this.PropertyChanging(this, emptyChangingEventArgs); this.PropertyChanging(this, emptyChangingEventArgs);
} }
} }
protected virtual void SendPropertyChanged(String propertyName) protected virtual void SendPropertyChanged(String propertyName)
{ {
if ((this.PropertyChanged != null)) if ((this.PropertyChanged != null))
{ {
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
} }
} }
} }
} }
#pragma warning restore 1591 #pragma warning restore 1591
#endif #endif
\ No newline at end of file
...@@ -13,232 +13,232 @@ ...@@ -13,232 +13,232 @@
#pragma warning disable RCS1023 // Format empty block. #pragma warning disable RCS1023 // Format empty block.
namespace PetaPoco namespace PetaPoco
{ {
// Poco's marked [Explicit] require all column properties to be marked // Poco's marked [Explicit] require all column properties to be marked
[AttributeUsage(AttributeTargets.Class)] [AttributeUsage(AttributeTargets.Class)]
public class ExplicitColumns : Attribute public class ExplicitColumns : Attribute
{ {
} }
// For non-explicit pocos, causes a property to be ignored // For non-explicit pocos, causes a property to be ignored
[AttributeUsage(AttributeTargets.Property)] [AttributeUsage(AttributeTargets.Property)]
public class Ignore : Attribute public class Ignore : Attribute
{ {
} }
// For explicit pocos, marks property as a column and optionally supplies column name // For explicit pocos, marks property as a column and optionally supplies column name
[AttributeUsage(AttributeTargets.Property)] [AttributeUsage(AttributeTargets.Property)]
public class Column : Attribute public class Column : Attribute
{ {
public Column() { } public Column() { }
public Column(string name) { Name = name; } public Column(string name) { Name = name; }
public string Name { get; set; } public string Name { get; set; }
} }
// For explicit pocos, marks property as a result column and optionally supplies column name // For explicit pocos, marks property as a result column and optionally supplies column name
[AttributeUsage(AttributeTargets.Property)] [AttributeUsage(AttributeTargets.Property)]
public class ResultColumn : Column public class ResultColumn : Column
{ {
public ResultColumn() { } public ResultColumn() { }
public ResultColumn(string name) : base(name) { } public ResultColumn(string name) : base(name) { }
} }
// Specify the table name of a poco // Specify the table name of a poco
[AttributeUsage(AttributeTargets.Class)] [AttributeUsage(AttributeTargets.Class)]
public class TableName : Attribute public class TableName : Attribute
{ {
public TableName(string tableName) public TableName(string tableName)
{ {
Value = tableName; Value = tableName;
} }
public string Value { get; } public string Value { get; }
} }
// Specific the primary key of a poco class // Specific the primary key of a poco class
[AttributeUsage(AttributeTargets.Class)] [AttributeUsage(AttributeTargets.Class)]
public class PrimaryKey : Attribute public class PrimaryKey : Attribute
{ {
public PrimaryKey(string primaryKey) public PrimaryKey(string primaryKey)
{ {
Value = primaryKey; Value = primaryKey;
} }
public string Value { get; } public string Value { get; }
} }
// Results from paged request // Results from paged request
public class Page<T> where T : new() public class Page<T> where T : new()
{ {
public long CurrentPage { get; set; } public long CurrentPage { get; set; }
public long TotalPages { get; set; } public long TotalPages { get; set; }
public long TotalItems { get; set; } public long TotalItems { get; set; }
public long ItemsPerPage { get; set; } public long ItemsPerPage { get; set; }
public List<T> Items { get; set; } public List<T> Items { get; set; }
} }
// Optionally provide and implementation of this to Database.Mapper // Optionally provide and implementation of this to Database.Mapper
public interface IMapper public interface IMapper
{ {
void GetTableInfo(Type t, ref string tableName, ref string primaryKey); void GetTableInfo(Type t, ref string tableName, ref string primaryKey);
bool MapPropertyToColumn(PropertyInfo pi, ref string columnName, ref bool resultColumn); bool MapPropertyToColumn(PropertyInfo pi, ref string columnName, ref bool resultColumn);
Func<object, object> GetValueConverter(PropertyInfo pi, Type SourceType); Func<object, object> GetValueConverter(PropertyInfo pi, Type SourceType);
} }
// Database class ... this is where most of the action happens // Database class ... this is where most of the action happens
public class Database : IDisposable public class Database : IDisposable
{ {
public Database(DbConnection connection) public Database(DbConnection connection)
{ {
_sharedConnection = connection; _sharedConnection = connection;
_connectionString = connection.ConnectionString; _connectionString = connection.ConnectionString;
_sharedConnectionDepth = 2; // Prevent closing external connection _sharedConnectionDepth = 2; // Prevent closing external connection
CommonConstruct(); CommonConstruct();
} }
public Database(string connectionString, string providerName) public Database(string connectionString, string providerName)
{ {
_connectionString = connectionString; _connectionString = connectionString;
_providerName = providerName; _providerName = providerName;
CommonConstruct(); CommonConstruct();
} }
public Database(string connectionStringName) public Database(string connectionStringName)
{ {
// Use first? // Use first?
if (connectionStringName == string.Empty) if (connectionStringName == string.Empty)
connectionStringName = ConfigurationManager.ConnectionStrings[0].Name; connectionStringName = ConfigurationManager.ConnectionStrings[0].Name;
// Work out connection string and provider name // Work out connection string and provider name
var providerName = "System.Data.SqlClient"; var providerName = "System.Data.SqlClient";
if (ConfigurationManager.ConnectionStrings[connectionStringName] != null) if (ConfigurationManager.ConnectionStrings[connectionStringName] != null)
{ {
if (!string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName)) if (!string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName))
providerName = ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName; providerName = ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName;
} }
else else
{ {
throw new InvalidOperationException("Can't find a connection string with the name '" + connectionStringName + "'"); throw new InvalidOperationException("Can't find a connection string with the name '" + connectionStringName + "'");
} }
// Store factory and connection string // Store factory and connection string
_connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString; _connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
_providerName = providerName; _providerName = providerName;
CommonConstruct(); CommonConstruct();
} }
private private
// Common initialization // Common initialization
void CommonConstruct() void CommonConstruct()
{ {
_transactionDepth = 0; _transactionDepth = 0;
EnableAutoSelect = true; EnableAutoSelect = true;
EnableNamedParams = true; EnableNamedParams = true;
ForceDateTimesToUtc = true; ForceDateTimesToUtc = true;
if (_providerName != null) if (_providerName != null)
_factory = DbProviderFactories.GetFactory(_providerName); _factory = DbProviderFactories.GetFactory(_providerName);
if (_connectionString?.IndexOf("Allow User Variables=true") >= 0 && IsMySql()) if (_connectionString?.IndexOf("Allow User Variables=true") >= 0 && IsMySql())
_paramPrefix = "?"; _paramPrefix = "?";
} }
// Automatically close one open shared connection // Automatically close one open shared connection
public void Dispose() public void Dispose()
{ {
if (_sharedConnectionDepth > 0) if (_sharedConnectionDepth > 0)
CloseSharedConnection(); CloseSharedConnection();
} }
// Who are we talking too? // Who are we talking too?
private bool IsMySql() { return string.Compare(_providerName, "MySql.Data.MySqlClient", true) == 0; } private bool IsMySql() { return string.Compare(_providerName, "MySql.Data.MySqlClient", true) == 0; }
private bool IsSqlServer() { return string.Compare(_providerName, "System.Data.SqlClient", true) == 0; } private bool IsSqlServer() { return string.Compare(_providerName, "System.Data.SqlClient", true) == 0; }
// Open a connection (can be nested) // Open a connection (can be nested)
public void OpenSharedConnection() public void OpenSharedConnection()
{ {
if (_sharedConnectionDepth == 0) if (_sharedConnectionDepth == 0)
{ {
_sharedConnection = _factory.CreateConnection(); _sharedConnection = _factory.CreateConnection();
_sharedConnection.ConnectionString = _connectionString; _sharedConnection.ConnectionString = _connectionString;
_sharedConnection.Open(); _sharedConnection.Open();
} }
_sharedConnectionDepth++; _sharedConnectionDepth++;
} }
// Close a previously opened connection // Close a previously opened connection
public void CloseSharedConnection() public void CloseSharedConnection()
{ {
_sharedConnectionDepth--; _sharedConnectionDepth--;
if (_sharedConnectionDepth == 0) if (_sharedConnectionDepth == 0)
{ {
_sharedConnection.Dispose(); _sharedConnection.Dispose();
_sharedConnection = null; _sharedConnection = null;
} }
} }
// Helper to create a transaction scope // Helper to create a transaction scope
public Transaction Transaction => new Transaction(this); public Transaction Transaction => new Transaction(this);
// Use by derived repo generated by T4 templates // Use by derived repo generated by T4 templates
public virtual void OnBeginTransaction() { } public virtual void OnBeginTransaction() { }
public virtual void OnEndTransaction() { } public virtual void OnEndTransaction() { }
// Start a new transaction, can be nested, every call must be // Start a new transaction, can be nested, every call must be
// matched by a call to AbortTransaction or CompleteTransaction // matched by a call to AbortTransaction or CompleteTransaction
// Use `using (var scope=db.Transaction) { scope.Complete(); }` to ensure correct semantics // Use `using (var scope=db.Transaction) { scope.Complete(); }` to ensure correct semantics
public void BeginTransaction() public void BeginTransaction()
{ {
_transactionDepth++; _transactionDepth++;
if (_transactionDepth == 1) if (_transactionDepth == 1)
{ {
OpenSharedConnection(); OpenSharedConnection();
_transaction = _sharedConnection.BeginTransaction(); _transaction = _sharedConnection.BeginTransaction();
_transactionCancelled = false; _transactionCancelled = false;
OnBeginTransaction(); OnBeginTransaction();
} }
} }
private private
// Internal helper to cleanup transaction stuff // Internal helper to cleanup transaction stuff
void CleanupTransaction() void CleanupTransaction()
{ {
OnEndTransaction(); OnEndTransaction();
if (_transactionCancelled) if (_transactionCancelled)
_transaction.Rollback(); _transaction.Rollback();
else else
_transaction.Commit(); _transaction.Commit();
_transaction.Dispose(); _transaction.Dispose();
_transaction = null; _transaction = null;
CloseSharedConnection(); CloseSharedConnection();
} }
// Abort the entire outer most transaction scope // Abort the entire outer most transaction scope
public void AbortTransaction() public void AbortTransaction()
{ {
_transactionCancelled = true; _transactionCancelled = true;
if ((--_transactionDepth) == 0) if ((--_transactionDepth) == 0)
CleanupTransaction(); CleanupTransaction();
} }
// Complete the transaction // Complete the transaction
public void CompleteTransaction() public void CompleteTransaction()
{ {
if ((--_transactionDepth) == 0) if ((--_transactionDepth) == 0)
CleanupTransaction(); CleanupTransaction();
} }
// Helper to handle named parameters from object properties // Helper to handle named parameters from object properties
private static readonly Regex rxParams = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled); private static readonly Regex rxParams = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
public static string ProcessParams(string _sql, object[] args_src, List<object> args_dest) public static string ProcessParams(string _sql, object[] args_src, List<object> args_dest)
{ {
return rxParams.Replace(_sql, m => return rxParams.Replace(_sql, m =>
{ {
string param = m.Value.Substring(1); string param = m.Value.Substring(1);
if (int.TryParse(param, out int paramIndex)) if (int.TryParse(param, out int paramIndex))
{ {
...@@ -267,688 +267,688 @@ public static string ProcessParams(string _sql, object[] args_src, List<object> ...@@ -267,688 +267,688 @@ public static string ProcessParams(string _sql, object[] args_src, List<object>
} }
return "@" + (args_dest.Count - 1).ToString(); return "@" + (args_dest.Count - 1).ToString();
} }
); );
} }
// Add a parameter to a DB command // Add a parameter to a DB command
private static void AddParam(DbCommand cmd, object item, string ParameterPrefix) private static void AddParam(DbCommand cmd, object item, string ParameterPrefix)
{ {
var p = cmd.CreateParameter(); var p = cmd.CreateParameter();
p.ParameterName = string.Format("{0}{1}", ParameterPrefix, cmd.Parameters.Count); p.ParameterName = string.Format("{0}{1}", ParameterPrefix, cmd.Parameters.Count);
if (item == null) if (item == null)
{ {
p.Value = DBNull.Value; p.Value = DBNull.Value;
} }
else else
{ {
if (item.GetType() == typeof(Guid)) if (item.GetType() == typeof(Guid))
{ {
p.Value = item.ToString(); p.Value = item.ToString();
p.DbType = DbType.String; p.DbType = DbType.String;
p.Size = 4000; p.Size = 4000;
} }
else if (item.GetType() == typeof(string)) else if (item.GetType() == typeof(string))
{ {
p.Size = (item as string).Length + 1; p.Size = (item as string).Length + 1;
if (p.Size < 4000) if (p.Size < 4000)
p.Size = 4000; p.Size = 4000;
p.Value = item; p.Value = item;
} }
else else
{ {
p.Value = item; p.Value = item;
} }
} }
cmd.Parameters.Add(p); cmd.Parameters.Add(p);
} }
// Create a command // Create a command
public DbCommand CreateCommand(DbConnection connection, string sql, params object[] args) public DbCommand CreateCommand(DbConnection connection, string sql, params object[] args)
{ {
if (EnableNamedParams) if (EnableNamedParams)
{ {
// Perform named argument replacements // Perform named argument replacements
var new_args = new List<object>(); var new_args = new List<object>();
sql = ProcessParams(sql, args, new_args); sql = ProcessParams(sql, args, new_args);
args = new_args.ToArray(); args = new_args.ToArray();
} }
// If we're in MySQL "Allow User Variables", we need to fix up parameter prefixes // If we're in MySQL "Allow User Variables", we need to fix up parameter prefixes
if (_paramPrefix == "?") if (_paramPrefix == "?")
{ {
// Convert "@parameter" -> "?parameter" // Convert "@parameter" -> "?parameter"
Regex paramReg = new Regex(@"(?<!@)@\w+"); Regex paramReg = new Regex(@"(?<!@)@\w+");
sql = paramReg.Replace(sql, m => "?" + m.Value.Substring(1)); sql = paramReg.Replace(sql, m => "?" + m.Value.Substring(1));
// Convert @@uservar -> @uservar and @@@systemvar -> @@systemvar // Convert @@uservar -> @uservar and @@@systemvar -> @@systemvar
sql = sql.Replace("@@", "@"); sql = sql.Replace("@@", "@");
} }
// Save the last sql and args // Save the last sql and args
_lastSql = sql; _lastSql = sql;
_lastArgs = args; _lastArgs = args;
DbCommand cmd = connection.CreateCommand(); DbCommand cmd = connection.CreateCommand();
cmd.CommandText = sql; cmd.CommandText = sql;
cmd.Transaction = _transaction; cmd.Transaction = _transaction;
foreach (var item in args) foreach (var item in args)
{ {
var p = cmd.CreateParameter(); var p = cmd.CreateParameter();
p.ParameterName = string.Format("{0}{1}", _paramPrefix, cmd.Parameters.Count); p.ParameterName = string.Format("{0}{1}", _paramPrefix, cmd.Parameters.Count);
if (item == null) if (item == null)
{ {
p.Value = DBNull.Value; p.Value = DBNull.Value;
} }
else else
{ {
if (item.GetType() == typeof(Guid)) if (item.GetType() == typeof(Guid))
{ {
p.Value = item.ToString(); p.Value = item.ToString();
p.DbType = DbType.String; p.DbType = DbType.String;
p.Size = 4000; p.Size = 4000;
} }
else if (item.GetType() == typeof(string)) else if (item.GetType() == typeof(string))
{ {
p.Size = (item as string).Length + 1; p.Size = (item as string).Length + 1;
if (p.Size < 4000) if (p.Size < 4000)
p.Size = 4000; p.Size = 4000;
p.Value = item; p.Value = item;
} }
else else
{ {
p.Value = item; p.Value = item;
} }
} }
cmd.Parameters.Add(p); cmd.Parameters.Add(p);
} }
return cmd; return cmd;
} }
// Override this to log/capture exceptions // Override this to log/capture exceptions
public virtual void OnException(Exception x) public virtual void OnException(Exception x)
{ {
System.Diagnostics.Debug.WriteLine(x.ToString()); System.Diagnostics.Debug.WriteLine(x.ToString());
System.Diagnostics.Debug.WriteLine(LastCommand); System.Diagnostics.Debug.WriteLine(LastCommand);
} }
// Execute a non-query command // Execute a non-query command
public int Execute(string sql, params object[] args) public int Execute(string sql, params object[] args)
{ {
try try
{ {
OpenSharedConnection(); OpenSharedConnection();
try try
{ {
using (var cmd = CreateCommand(_sharedConnection, sql, args)) using (var cmd = CreateCommand(_sharedConnection, sql, args))
{ {
return cmd.ExecuteNonQuery(); return cmd.ExecuteNonQuery();
} }
} }
finally finally
{ {
CloseSharedConnection(); CloseSharedConnection();
} }
} }
catch (Exception x) catch (Exception x)
{ {
OnException(x); OnException(x);
throw; throw;
} }
} }
public int Execute(Sql sql) public int Execute(Sql sql)
{ {
return Execute(sql.SQL, sql.Arguments); return Execute(sql.SQL, sql.Arguments);
} }
// Execute and cast a scalar property // Execute and cast a scalar property
public T ExecuteScalar<T>(string sql, params object[] args) public T ExecuteScalar<T>(string sql, params object[] args)
{ {
try try
{ {
OpenSharedConnection(); OpenSharedConnection();
try try
{ {
using (var cmd = CreateCommand(_sharedConnection, sql, args)) using (var cmd = CreateCommand(_sharedConnection, sql, args))
{ {
object val = cmd.ExecuteScalar(); object val = cmd.ExecuteScalar();
return (T)Convert.ChangeType(val, typeof(T)); return (T)Convert.ChangeType(val, typeof(T));
} }
} }
finally finally
{ {
CloseSharedConnection(); CloseSharedConnection();
} }
} }
catch (Exception x) catch (Exception x)
{ {
OnException(x); OnException(x);
throw; throw;
} }
} }
public T ExecuteScalar<T>(Sql sql) public T ExecuteScalar<T>(Sql sql)
{ {
return ExecuteScalar<T>(sql.SQL, sql.Arguments); return ExecuteScalar<T>(sql.SQL, sql.Arguments);
} }
private readonly Regex rxSelect = new Regex(@"^\s*SELECT\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline); private readonly Regex rxSelect = new Regex(@"^\s*SELECT\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
private string AddSelectClause<T>(string sql) private string AddSelectClause<T>(string sql)
{ {
// Already present? // Already present?
if (rxSelect.IsMatch(sql)) if (rxSelect.IsMatch(sql))
return sql; return sql;
// Get the poco data for this type // Get the poco data for this type
var pd = PocoData.ForType(typeof(T)); var pd = PocoData.ForType(typeof(T));
return string.Format("SELECT {0} FROM {1} {2}", pd.QueryColumns, pd.TableName, sql); return string.Format("SELECT {0} FROM {1} {2}", pd.QueryColumns, pd.TableName, sql);
} }
public bool EnableAutoSelect { get; set; } public bool EnableAutoSelect { get; set; }
public bool EnableNamedParams { get; set; } public bool EnableNamedParams { get; set; }
public bool ForceDateTimesToUtc { get; set; } public bool ForceDateTimesToUtc { get; set; }
// Return a typed list of pocos // Return a typed list of pocos
public List<T> Fetch<T>(string sql, params object[] args) where T : new() public List<T> Fetch<T>(string sql, params object[] args) where T : new()
{ {
// Auto select clause? // Auto select clause?
if (EnableAutoSelect) if (EnableAutoSelect)
sql = AddSelectClause<T>(sql); sql = AddSelectClause<T>(sql);
try try
{ {
OpenSharedConnection(); OpenSharedConnection();
try try
{ {
using (var cmd = CreateCommand(_sharedConnection, sql, args)) using (var cmd = CreateCommand(_sharedConnection, sql, args))
{ {
using (var r = cmd.ExecuteReader()) using (var r = cmd.ExecuteReader())
{ {
var l = new List<T>(); var l = new List<T>();
var pd = PocoData.ForType(typeof(T)); var pd = PocoData.ForType(typeof(T));
var factory = pd.GetFactory<T>(sql + "-" + _sharedConnection.ConnectionString + ForceDateTimesToUtc.ToString(), ForceDateTimesToUtc, r); var factory = pd.GetFactory<T>(sql + "-" + _sharedConnection.ConnectionString + ForceDateTimesToUtc.ToString(), ForceDateTimesToUtc, r);
while (r.Read()) while (r.Read())
{ {
l.Add(factory(r)); l.Add(factory(r));
} }
return l; return l;
} }
} }
} }
finally finally
{ {
CloseSharedConnection(); CloseSharedConnection();
} }
} }
catch (Exception x) catch (Exception x)
{ {
OnException(x); OnException(x);
throw; throw;
} }
} }
// Optimized version when only needing a single record // Optimized version when only needing a single record
public T FirstOrDefault<T>(string sql, params object[] args) where T : new() public T FirstOrDefault<T>(string sql, params object[] args) where T : new()
{ {
// Auto select clause? // Auto select clause?
if (EnableAutoSelect) if (EnableAutoSelect)
sql = AddSelectClause<T>(sql); sql = AddSelectClause<T>(sql);
try try
{ {
OpenSharedConnection(); OpenSharedConnection();
try try
{ {
using (var cmd = CreateCommand(_sharedConnection, sql, args)) using (var cmd = CreateCommand(_sharedConnection, sql, args))
{ {
using (var r = cmd.ExecuteReader()) using (var r = cmd.ExecuteReader())
{ {
if (!r.Read()) if (!r.Read())
return default(T); return default(T);
var pd = PocoData.ForType(typeof(T)); var pd = PocoData.ForType(typeof(T));
var factory = pd.GetFactory<T>(sql + "-" + _sharedConnection.ConnectionString + ForceDateTimesToUtc.ToString(), ForceDateTimesToUtc, r); var factory = pd.GetFactory<T>(sql + "-" + _sharedConnection.ConnectionString + ForceDateTimesToUtc.ToString(), ForceDateTimesToUtc, r);
return factory(r); return factory(r);
} }
} }
} }
finally finally
{ {
CloseSharedConnection(); CloseSharedConnection();
} }
} }
catch (Exception x) catch (Exception x)
{ {
OnException(x); OnException(x);
throw; throw;
} }
} }
// Optimized version when only wanting a single record // Optimized version when only wanting a single record
public T SingleOrDefault<T>(string sql, params object[] args) where T : new() public T SingleOrDefault<T>(string sql, params object[] args) where T : new()
{ {
// Auto select clause? // Auto select clause?
if (EnableAutoSelect) if (EnableAutoSelect)
sql = AddSelectClause<T>(sql); sql = AddSelectClause<T>(sql);
try try
{ {
OpenSharedConnection(); OpenSharedConnection();
try try
{ {
using (var cmd = CreateCommand(_sharedConnection, sql, args)) using (var cmd = CreateCommand(_sharedConnection, sql, args))
{ {
using (var r = cmd.ExecuteReader()) using (var r = cmd.ExecuteReader())
{ {
if (!r.Read()) if (!r.Read())
return default(T); return default(T);
var pd = PocoData.ForType(typeof(T)); var pd = PocoData.ForType(typeof(T));
var factory = pd.GetFactory<T>(sql + "-" + _sharedConnection.ConnectionString + ForceDateTimesToUtc.ToString(), ForceDateTimesToUtc, r); var factory = pd.GetFactory<T>(sql + "-" + _sharedConnection.ConnectionString + ForceDateTimesToUtc.ToString(), ForceDateTimesToUtc, r);
T ret = factory(r); T ret = factory(r);
if (r.Read()) if (r.Read())
throw new InvalidOperationException("Sequence contains more than one element"); throw new InvalidOperationException("Sequence contains more than one element");
return ret; return ret;
} }
} }
} }
finally finally
{ {
CloseSharedConnection(); CloseSharedConnection();
} }
} }
catch (Exception x) catch (Exception x)
{ {
OnException(x); OnException(x);
throw; throw;
} }
} }
// Warning: scary regex follows // Warning: scary regex follows
private static readonly Regex rxColumns = new Regex(@"^\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b", private static readonly Regex rxColumns = new Regex(@"^\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b",
RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled); RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
private static readonly Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*", private static readonly Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*",
RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled); RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
public static bool SplitSqlForPaging(string sql, out string sqlCount, out string sqlSelectRemoved, out string sqlOrderBy) public static bool SplitSqlForPaging(string sql, out string sqlCount, out string sqlSelectRemoved, out string sqlOrderBy)
{ {
sqlSelectRemoved = null; sqlSelectRemoved = null;
sqlCount = null; sqlCount = null;
sqlOrderBy = null; sqlOrderBy = null;
// Extract the columns from "SELECT <whatever> FROM" // Extract the columns from "SELECT <whatever> FROM"
var m = rxColumns.Match(sql); var m = rxColumns.Match(sql);
if (!m.Success) if (!m.Success)
return false; return false;
// Save column list and replace with COUNT(*) // Save column list and replace with COUNT(*)
Group g = m.Groups[1]; Group g = m.Groups[1];
sqlCount = sql.Substring(0, g.Index) + "COUNT(*) " + sql.Substring(g.Index + g.Length); sqlCount = sql.Substring(0, g.Index) + "COUNT(*) " + sql.Substring(g.Index + g.Length);
sqlSelectRemoved = sql.Substring(g.Index); sqlSelectRemoved = sql.Substring(g.Index);
// Look for an "ORDER BY <whatever>" clause // Look for an "ORDER BY <whatever>" clause
m = rxOrderBy.Match(sqlCount); m = rxOrderBy.Match(sqlCount);
if (!m.Success) if (!m.Success)
return false; return false;
g = m.Groups[0]; g = m.Groups[0];
sqlOrderBy = g.ToString(); sqlOrderBy = g.ToString();
sqlCount = sqlCount.Substring(0, g.Index) + sqlCount.Substring(g.Index + g.Length); sqlCount = sqlCount.Substring(0, g.Index) + sqlCount.Substring(g.Index + g.Length);
return true; return true;
} }
// Fetch a page // Fetch a page
public Page<T> Page<T>(long page, long itemsPerPage, string sql, params object[] args) where T : new() public Page<T> Page<T>(long page, long itemsPerPage, string sql, params object[] args) where T : new()
{ {
// Add auto select clause // Add auto select clause
if (EnableAutoSelect) if (EnableAutoSelect)
sql = AddSelectClause<T>(sql); sql = AddSelectClause<T>(sql);
if (!SplitSqlForPaging(sql, out string sqlCount, out string sqlSelectRemoved, out string sqlOrderBy)) if (!SplitSqlForPaging(sql, out string sqlCount, out string sqlSelectRemoved, out string sqlOrderBy))
throw new Exception("Unable to parse SQL statement for paged query"); throw new Exception("Unable to parse SQL statement for paged query");
// Setup the paged result // Setup the paged result
var result = new Page<T>(); var result = new Page<T>();
result.CurrentPage = page; result.CurrentPage = page;
result.ItemsPerPage = itemsPerPage; result.ItemsPerPage = itemsPerPage;
result.TotalItems = ExecuteScalar<long>(sqlCount, args); result.TotalItems = ExecuteScalar<long>(sqlCount, args);
result.TotalPages = result.TotalItems / itemsPerPage; result.TotalPages = result.TotalItems / itemsPerPage;
if ((result.TotalItems % itemsPerPage) != 0) if ((result.TotalItems % itemsPerPage) != 0)
result.TotalPages++; result.TotalPages++;
// Build the SQL for the actual final result // Build the SQL for the actual final result
string sqlPage; string sqlPage;
if (IsSqlServer()) if (IsSqlServer())
{ {
// Ugh really? // Ugh really?
sqlSelectRemoved = rxOrderBy.Replace(sqlSelectRemoved, ""); sqlSelectRemoved = rxOrderBy.Replace(sqlSelectRemoved, "");
sqlPage = string.Format("SELECT * FROM (SELECT ROW_NUMBER() OVER ({0}) AS __rn, {1}) as __paged WHERE __rn>{2} AND __rn<={3}", sqlPage = string.Format("SELECT * FROM (SELECT ROW_NUMBER() OVER ({0}) AS __rn, {1}) as __paged WHERE __rn>{2} AND __rn<={3}",
sqlOrderBy, sqlSelectRemoved, (page - 1) * itemsPerPage, page * itemsPerPage); sqlOrderBy, sqlSelectRemoved, (page - 1) * itemsPerPage, page * itemsPerPage);
} }
else else
{ {
// Nice // Nice
sqlPage = string.Format("{0}\nLIMIT {1} OFFSET {2}", sql, itemsPerPage, (page - 1) * itemsPerPage); sqlPage = string.Format("{0}\nLIMIT {1} OFFSET {2}", sql, itemsPerPage, (page - 1) * itemsPerPage);
} }
// Get the records // Get the records
result.Items = Fetch<T>(sqlPage, args); result.Items = Fetch<T>(sqlPage, args);
// Done // Done
return result; return result;
} }
public Page<T> Page<T>(long page, long itemsPerPage, Sql sql) where T : new() public Page<T> Page<T>(long page, long itemsPerPage, Sql sql) where T : new()
{ {
return Page<T>(page, itemsPerPage, sql.SQL, sql.Arguments); return Page<T>(page, itemsPerPage, sql.SQL, sql.Arguments);
} }
// Return an enumerable collection of pocos // Return an enumerable collection of pocos
public IEnumerable<T> Query<T>(string sql, params object[] args) where T : new() public IEnumerable<T> Query<T>(string sql, params object[] args) where T : new()
{ {
if (EnableAutoSelect) if (EnableAutoSelect)
sql = AddSelectClause<T>(sql); sql = AddSelectClause<T>(sql);
using (var conn = new ShareableConnection(this)) using (var conn = new ShareableConnection(this))
{ {
using (var cmd = CreateCommand(conn.Connection, sql, args)) using (var cmd = CreateCommand(conn.Connection, sql, args))
{ {
IDataReader r; IDataReader r;
var pd = PocoData.ForType(typeof(T)); var pd = PocoData.ForType(typeof(T));
try try
{ {
r = cmd.ExecuteReader(); r = cmd.ExecuteReader();
} }
catch (Exception x) catch (Exception x)
{ {
OnException(x); OnException(x);
throw; throw;
} }
var factory = pd.GetFactory<T>(sql + "-" + conn.Connection.ConnectionString + ForceDateTimesToUtc.ToString(), ForceDateTimesToUtc, r); var factory = pd.GetFactory<T>(sql + "-" + conn.Connection.ConnectionString + ForceDateTimesToUtc.ToString(), ForceDateTimesToUtc, r);
using (r) using (r)
{ {
while (true) while (true)
{ {
T poco; T poco;
try try
{ {
if (!r.Read()) if (!r.Read())
yield break; yield break;
poco = factory(r); poco = factory(r);
} }
catch (Exception x) catch (Exception x)
{ {
OnException(x); OnException(x);
throw; throw;
} }
yield return poco; yield return poco;
} }
} }
} }
} }
} }
public List<T> Fetch<T>(Sql sql) where T : new() public List<T> Fetch<T>(Sql sql) where T : new()
{ {
return Fetch<T>(sql.SQL, sql.Arguments); return Fetch<T>(sql.SQL, sql.Arguments);
} }
public IEnumerable<T> Query<T>(Sql sql) where T : new() public IEnumerable<T> Query<T>(Sql sql) where T : new()
{ {
return Query<T>(sql.SQL, sql.Arguments); return Query<T>(sql.SQL, sql.Arguments);
} }
public T Single<T>(string sql, params object[] args) where T : new() public T Single<T>(string sql, params object[] args) where T : new()
{ {
T val = SingleOrDefault<T>(sql, args); T val = SingleOrDefault<T>(sql, args);
if (!EqualityComparer<T>.Default.Equals(val, default(T))) if (!EqualityComparer<T>.Default.Equals(val, default(T)))
return val; return val;
else else
throw new InvalidOperationException("The sequence contains no elements"); throw new InvalidOperationException("The sequence contains no elements");
} }
public T First<T>(string sql, params object[] args) where T : new() public T First<T>(string sql, params object[] args) where T : new()
{ {
T val = FirstOrDefault<T>(sql, args); T val = FirstOrDefault<T>(sql, args);
if (!EqualityComparer<T>.Default.Equals(val, default(T))) if (!EqualityComparer<T>.Default.Equals(val, default(T)))
return val; return val;
else else
throw new InvalidOperationException("The sequence contains no elements"); throw new InvalidOperationException("The sequence contains no elements");
} }
public T Single<T>(Sql sql) where T : new() public T Single<T>(Sql sql) where T : new()
{ {
return Single<T>(sql.SQL, sql.Arguments); return Single<T>(sql.SQL, sql.Arguments);
} }
public T SingleOrDefault<T>(Sql sql) where T : new() public T SingleOrDefault<T>(Sql sql) where T : new()
{ {
return SingleOrDefault<T>(sql.SQL, sql.Arguments); return SingleOrDefault<T>(sql.SQL, sql.Arguments);
} }
public T FirstOrDefault<T>(Sql sql) where T : new() public T FirstOrDefault<T>(Sql sql) where T : new()
{ {
return FirstOrDefault<T>(sql.SQL, sql.Arguments); return FirstOrDefault<T>(sql.SQL, sql.Arguments);
} }
public T First<T>(Sql sql) where T : new() public T First<T>(Sql sql) where T : new()
{ {
return First<T>(sql.SQL, sql.Arguments); return First<T>(sql.SQL, sql.Arguments);
} }
// Insert a poco into a table. If the poco has a property with the same name // Insert a poco into a table. If the poco has a property with the same name
// as the primary key the id of the new record is assigned to it. Either way, // as the primary key the id of the new record is assigned to it. Either way,
// the new id is returned. // the new id is returned.
public object Insert(string tableName, string primaryKeyName, object poco) public object Insert(string tableName, string primaryKeyName, object poco)
{ {
try try
{ {
OpenSharedConnection(); OpenSharedConnection();
try try
{ {
using (var cmd = CreateCommand(_sharedConnection, "")) using (var cmd = CreateCommand(_sharedConnection, ""))
{ {
var pd = PocoData.ForType(poco.GetType()); var pd = PocoData.ForType(poco.GetType());
var names = new List<string>(); var names = new List<string>();
var values = new List<string>(); var values = new List<string>();
var index = 0; var index = 0;
foreach (var i in pd.Columns) foreach (var i in pd.Columns)
{ {
// Don't insert the primary key or result only columns // Don't insert the primary key or result only columns
if ((primaryKeyName != null && i.Key == primaryKeyName) || i.Value.ResultColumn) if ((primaryKeyName != null && i.Key == primaryKeyName) || i.Value.ResultColumn)
continue; continue;
names.Add(i.Key); names.Add(i.Key);
values.Add(string.Format("{0}{1}", _paramPrefix, index++)); values.Add(string.Format("{0}{1}", _paramPrefix, index++));
AddParam(cmd, i.Value.PropertyInfo.GetValue(poco, null), _paramPrefix); AddParam(cmd, i.Value.PropertyInfo.GetValue(poco, null), _paramPrefix);
} }
cmd.CommandText = string.Format("INSERT INTO {0} ({1}) VALUES ({2}); SELECT @@IDENTITY AS NewID;", cmd.CommandText = string.Format("INSERT INTO {0} ({1}) VALUES ({2}); SELECT @@IDENTITY AS NewID;",
tableName, tableName,
string.Join(",", names.ToArray()), string.Join(",", names.ToArray()),
string.Join(",", values.ToArray()) string.Join(",", values.ToArray())
); );
_lastSql = cmd.CommandText; _lastSql = cmd.CommandText;
_lastArgs = values.ToArray(); _lastArgs = values.ToArray();
// Insert the record, should get back it's ID // Insert the record, should get back it's ID
var id = cmd.ExecuteScalar(); var id = cmd.ExecuteScalar();
// Assign the ID back to the primary key property // Assign the ID back to the primary key property
if (primaryKeyName != null) if (primaryKeyName != null)
{ {
if (pd.Columns.TryGetValue(primaryKeyName, out PocoColumn pc)) if (pd.Columns.TryGetValue(primaryKeyName, out PocoColumn pc))
{ {
pc.PropertyInfo.SetValue(poco, Convert.ChangeType(id, pc.PropertyInfo.PropertyType), null); pc.PropertyInfo.SetValue(poco, Convert.ChangeType(id, pc.PropertyInfo.PropertyType), null);
} }
} }
return id; return id;
} }
} }
finally finally
{ {
CloseSharedConnection(); CloseSharedConnection();
} }
} }
catch (Exception x) catch (Exception x)
{ {
OnException(x); OnException(x);
throw; throw;
} }
} }
// Insert an annotated poco object // Insert an annotated poco object
public object Insert(object poco) public object Insert(object poco)
{ {
var pd = PocoData.ForType(poco.GetType()); var pd = PocoData.ForType(poco.GetType());
return Insert(pd.TableName, pd.PrimaryKey, poco); return Insert(pd.TableName, pd.PrimaryKey, poco);
} }
// Update a record with values from a poco. primary key value can be either supplied or read from the poco // Update a record with values from a poco. primary key value can be either supplied or read from the poco
public int Update(string tableName, string primaryKeyName, object poco, object primaryKeyValue) public int Update(string tableName, string primaryKeyName, object poco, object primaryKeyValue)
{ {
try try
{ {
OpenSharedConnection(); OpenSharedConnection();
try try
{ {
using (var cmd = CreateCommand(_sharedConnection, "")) using (var cmd = CreateCommand(_sharedConnection, ""))
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
var index = 0; var index = 0;
var pd = PocoData.ForType(poco.GetType()); var pd = PocoData.ForType(poco.GetType());
foreach (var i in pd.Columns) foreach (var i in pd.Columns)
{ {
// Don't update the primary key, but grab the value if we don't have it // Don't update the primary key, but grab the value if we don't have it
if (i.Key == primaryKeyName) if (i.Key == primaryKeyName)
{ {
primaryKeyValue = primaryKeyValue ?? i.Value.PropertyInfo.GetValue(poco, null); primaryKeyValue = primaryKeyValue ?? i.Value.PropertyInfo.GetValue(poco, null);
continue; continue;
} }
// Dont update result only columns // Dont update result only columns
if (i.Value.ResultColumn) if (i.Value.ResultColumn)
continue; continue;
// Build the sql // Build the sql
if (index > 0) if (index > 0)
sb.Append(", "); sb.Append(", ");
sb.AppendFormat("{0} = {1}{2}", i.Key, _paramPrefix, index++); sb.AppendFormat("{0} = {1}{2}", i.Key, _paramPrefix, index++);
// Store the parameter in the command // Store the parameter in the command
AddParam(cmd, i.Value.PropertyInfo.GetValue(poco, null), _paramPrefix); AddParam(cmd, i.Value.PropertyInfo.GetValue(poco, null), _paramPrefix);
} }
cmd.CommandText = string.Format("UPDATE {0} SET {1} WHERE {2} = {3}{4}", cmd.CommandText = string.Format("UPDATE {0} SET {1} WHERE {2} = {3}{4}",
tableName, tableName,
sb.ToString(), sb.ToString(),
primaryKeyName, primaryKeyName,
_paramPrefix, _paramPrefix,
index++ index++
); );
AddParam(cmd, primaryKeyValue, _paramPrefix); AddParam(cmd, primaryKeyValue, _paramPrefix);
_lastSql = cmd.CommandText; _lastSql = cmd.CommandText;
_lastArgs = new object[] { primaryKeyValue }; _lastArgs = new object[] { primaryKeyValue };
// Do it // Do it
return cmd.ExecuteNonQuery(); return cmd.ExecuteNonQuery();
} }
} }
finally finally
{ {
CloseSharedConnection(); CloseSharedConnection();
} }
} }
catch (Exception x) catch (Exception x)
{ {
OnException(x); OnException(x);
throw; throw;
} }
} }
public int Update(string tableName, string primaryKeyName, object poco) public int Update(string tableName, string primaryKeyName, object poco)
{ {
return Update(tableName, primaryKeyName, poco, null); return Update(tableName, primaryKeyName, poco, null);
} }
public int Update(object poco) public int Update(object poco)
{ {
return Update(poco, null); return Update(poco, null);
} }
public int Update(object poco, object primaryKeyValue) public int Update(object poco, object primaryKeyValue)
{ {
var pd = PocoData.ForType(poco.GetType()); var pd = PocoData.ForType(poco.GetType());
return Update(pd.TableName, pd.PrimaryKey, poco, primaryKeyValue); return Update(pd.TableName, pd.PrimaryKey, poco, primaryKeyValue);
} }
public int Update<T>(string sql, params object[] args) public int Update<T>(string sql, params object[] args)
{ {
var pd = PocoData.ForType(typeof(T)); var pd = PocoData.ForType(typeof(T));
return Execute(string.Format("UPDATE {0} {1}", pd.TableName, sql), args); return Execute(string.Format("UPDATE {0} {1}", pd.TableName, sql), args);
} }
public int Update<T>(Sql sql) public int Update<T>(Sql sql)
{ {
var pd = PocoData.ForType(typeof(T)); var pd = PocoData.ForType(typeof(T));
return Execute(new Sql(string.Format("UPDATE {0}", pd.TableName)).Append(sql)); return Execute(new Sql(string.Format("UPDATE {0}", pd.TableName)).Append(sql));
} }
public int Delete(string tableName, string primaryKeyName, object poco) public int Delete(string tableName, string primaryKeyName, object poco)
{ {
return Delete(tableName, primaryKeyName, poco, null); return Delete(tableName, primaryKeyName, poco, null);
} }
public int Delete(string tableName, string primaryKeyName, object poco, object primaryKeyValue) public int Delete(string tableName, string primaryKeyName, object poco, object primaryKeyValue)
{ {
// If primary key value not specified, pick it up from the object // If primary key value not specified, pick it up from the object
if (primaryKeyValue == null) if (primaryKeyValue == null)
{ {
var pd = PocoData.ForType(poco.GetType()); var pd = PocoData.ForType(poco.GetType());
if (pd.Columns.TryGetValue(primaryKeyName, out PocoColumn pc)) if (pd.Columns.TryGetValue(primaryKeyName, out PocoColumn pc))
{ {
primaryKeyValue = pc.PropertyInfo.GetValue(poco, null); primaryKeyValue = pc.PropertyInfo.GetValue(poco, null);
} }
} }
// Do it // Do it
var sql = string.Format("DELETE FROM {0} WHERE {1}=@0", tableName, primaryKeyName); var sql = string.Format("DELETE FROM {0} WHERE {1}=@0", tableName, primaryKeyName);
return Execute(sql, primaryKeyValue); return Execute(sql, primaryKeyValue);
} }
public int Delete(object poco) public int Delete(object poco)
{ {
var pd = PocoData.ForType(poco.GetType()); var pd = PocoData.ForType(poco.GetType());
return Delete(pd.TableName, pd.PrimaryKey, poco); return Delete(pd.TableName, pd.PrimaryKey, poco);
} }
public int Delete<T>(string sql, params object[] args) public int Delete<T>(string sql, params object[] args)
{ {
var pd = PocoData.ForType(typeof(T)); var pd = PocoData.ForType(typeof(T));
return Execute(string.Format("DELETE FROM {0} {1}", pd.TableName, sql), args); return Execute(string.Format("DELETE FROM {0} {1}", pd.TableName, sql), args);
} }
public int Delete<T>(Sql sql) public int Delete<T>(Sql sql)
{ {
var pd = PocoData.ForType(typeof(T)); var pd = PocoData.ForType(typeof(T));
return Execute(new Sql(string.Format("DELETE FROM {0}", pd.TableName)).Append(sql)); return Execute(new Sql(string.Format("DELETE FROM {0}", pd.TableName)).Append(sql));
} }
// Check if a poco represents a new record // Check if a poco represents a new record
public bool IsNew(string primaryKeyName, object poco) public bool IsNew(string primaryKeyName, object poco)
{ {
// If primary key value not specified, pick it up from the object // If primary key value not specified, pick it up from the object
var pd = PocoData.ForType(poco.GetType()); var pd = PocoData.ForType(poco.GetType());
PropertyInfo pi; PropertyInfo pi;
if (pd.Columns.TryGetValue(primaryKeyName, out PocoColumn pc)) if (pd.Columns.TryGetValue(primaryKeyName, out PocoColumn pc))
{ {
pi = pc.PropertyInfo; pi = pc.PropertyInfo;
...@@ -962,135 +962,135 @@ public bool IsNew(string primaryKeyName, object poco) ...@@ -962,135 +962,135 @@ public bool IsNew(string primaryKeyName, object poco)
// Get it's value // Get it's value
var pk = pi.GetValue(poco, null); var pk = pi.GetValue(poco, null);
if (pk == null) if (pk == null)
return true; return true;
var type = pk.GetType(); var type = pk.GetType();
if (type.IsValueType) if (type.IsValueType)
{ {
// Common primary key types // Common primary key types
if (type == typeof(long)) if (type == typeof(long))
return (long)pk == 0; return (long)pk == 0;
else if (type == typeof(ulong)) else if (type == typeof(ulong))
return (ulong)pk == 0; return (ulong)pk == 0;
else if (type == typeof(int)) else if (type == typeof(int))
return (int)pk == 0; return (int)pk == 0;
else if (type == typeof(uint)) else if (type == typeof(uint))
return (int)pk == 0; return (int)pk == 0;
// Create a default instance and compare // Create a default instance and compare
return pk == Activator.CreateInstance(pk.GetType()); return pk == Activator.CreateInstance(pk.GetType());
} }
else else
{ {
return pk == null; return pk == null;
} }
} }
public bool IsNew(object poco) public bool IsNew(object poco)
{ {
var pd = PocoData.ForType(poco.GetType()); var pd = PocoData.ForType(poco.GetType());
return IsNew(pd.PrimaryKey, poco); return IsNew(pd.PrimaryKey, poco);
} }
// Insert new record or Update existing record // Insert new record or Update existing record
public void Save(string tableName, string primaryKeyName, object poco) public void Save(string tableName, string primaryKeyName, object poco)
{ {
if (IsNew(primaryKeyName, poco)) if (IsNew(primaryKeyName, poco))
{ {
Insert(tableName, primaryKeyName, poco); Insert(tableName, primaryKeyName, poco);
} }
else else
{ {
Update(tableName, primaryKeyName, poco); Update(tableName, primaryKeyName, poco);
} }
} }
public void Save(object poco) public void Save(object poco)
{ {
var pd = PocoData.ForType(poco.GetType()); var pd = PocoData.ForType(poco.GetType());
Save(pd.TableName, pd.PrimaryKey, poco); Save(pd.TableName, pd.PrimaryKey, poco);
} }
public string LastSQL => _lastSql; public string LastSQL => _lastSql;
public object[] LastArgs => _lastArgs; public object[] LastArgs => _lastArgs;
public string LastCommand public string LastCommand
{ {
get get
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
if (_lastSql == null) if (_lastSql == null)
return ""; return "";
sb.Append(_lastSql); sb.Append(_lastSql);
if (_lastArgs != null) if (_lastArgs != null)
{ {
sb.Append("\r\n\r\n"); sb.Append("\r\n\r\n");
for (int i = 0; i < _lastArgs.Length; i++) for (int i = 0; i < _lastArgs.Length; i++)
{ {
sb.AppendFormat("{0} - {1}\r\n", i, _lastArgs[i].ToString()); sb.AppendFormat("{0} - {1}\r\n", i, _lastArgs[i].ToString());
} }
} }
return sb.ToString(); return sb.ToString();
} }
} }
public static IMapper Mapper { get; set; } public static IMapper Mapper { get; set; }
internal class PocoColumn internal class PocoColumn
{ {
public string ColumnName; public string ColumnName;
public PropertyInfo PropertyInfo; public PropertyInfo PropertyInfo;
public bool ResultColumn; public bool ResultColumn;
} }
internal class PocoData internal class PocoData
{ {
public static PocoData ForType(Type t) public static PocoData ForType(Type t)
{ {
lock (m_PocoData) lock (m_PocoData)
{ {
if (!m_PocoData.TryGetValue(t, out PocoData pd)) if (!m_PocoData.TryGetValue(t, out PocoData pd))
{ {
pd = new PocoData(t); pd = new PocoData(t);
m_PocoData.Add(t, pd); m_PocoData.Add(t, pd);
} }
return pd; return pd;
} }
} }
public PocoData(Type t) public PocoData(Type t)
{ {
// Get the table name // Get the table name
var a = t.GetCustomAttributes(typeof(TableName), true); var a = t.GetCustomAttributes(typeof(TableName), true);
var tempTableName = a.Length == 0 ? t.Name : (a[0] as TableName).Value; var tempTableName = a.Length == 0 ? t.Name : (a[0] as TableName).Value;
// Get the primary key // Get the primary key
a = t.GetCustomAttributes(typeof(PrimaryKey), true); a = t.GetCustomAttributes(typeof(PrimaryKey), true);
var tempPrimaryKey = a.Length == 0 ? "ID" : (a[0] as PrimaryKey).Value; var tempPrimaryKey = a.Length == 0 ? "ID" : (a[0] as PrimaryKey).Value;
// Call column mapper // Call column mapper
Database.Mapper?.GetTableInfo(t, ref tempTableName, ref tempPrimaryKey); Database.Mapper?.GetTableInfo(t, ref tempTableName, ref tempPrimaryKey);
TableName = tempTableName; TableName = tempTableName;
PrimaryKey = tempPrimaryKey; PrimaryKey = tempPrimaryKey;
// Work out bound properties // Work out bound properties
bool ExplicitColumns = t.GetCustomAttributes(typeof(ExplicitColumns), true).Length > 0; bool ExplicitColumns = t.GetCustomAttributes(typeof(ExplicitColumns), true).Length > 0;
Columns = new Dictionary<string, PocoColumn>(StringComparer.OrdinalIgnoreCase); Columns = new Dictionary<string, PocoColumn>(StringComparer.OrdinalIgnoreCase);
foreach (var pi in t.GetProperties()) foreach (var pi in t.GetProperties())
{ {
// Work out if properties is to be included // Work out if properties is to be included
var ColAttrs = pi.GetCustomAttributes(typeof(Column), true); var ColAttrs = pi.GetCustomAttributes(typeof(Column), true);
if (ExplicitColumns) if (ExplicitColumns)
{ {
if (ColAttrs.Length == 0) if (ColAttrs.Length == 0)
continue; continue;
} }
else else
{ {
if (pi.GetCustomAttributes(typeof(Ignore), true).Length != 0) if (pi.GetCustomAttributes(typeof(Ignore), true).Length != 0)
continue; continue;
} }
var pc = new PocoColumn() var pc = new PocoColumn()
{ {
...@@ -1099,166 +1099,166 @@ public PocoData(Type t) ...@@ -1099,166 +1099,166 @@ public PocoData(Type t)
// Work out the DB column name // Work out the DB column name
if (ColAttrs.Length > 0) if (ColAttrs.Length > 0)
{ {
var colattr = (Column)ColAttrs[0]; var colattr = (Column)ColAttrs[0];
pc.ColumnName = colattr.Name; pc.ColumnName = colattr.Name;
if (colattr is ResultColumn) if (colattr is ResultColumn)
pc.ResultColumn = true; pc.ResultColumn = true;
} }
if (pc.ColumnName == null) if (pc.ColumnName == null)
{ {
pc.ColumnName = pi.Name; pc.ColumnName = pi.Name;
if (Mapper?.MapPropertyToColumn(pi, ref pc.ColumnName, ref pc.ResultColumn) == false) if (Mapper?.MapPropertyToColumn(pi, ref pc.ColumnName, ref pc.ResultColumn) == false)
continue; continue;
} }
// Store it // Store it
Columns.Add(pc.ColumnName, pc); Columns.Add(pc.ColumnName, pc);
} }
// Build column list for automatic select // Build column list for automatic select
QueryColumns = string.Join(", ", (from c in Columns where !c.Value.ResultColumn select c.Key).ToArray()); QueryColumns = string.Join(", ", (from c in Columns where !c.Value.ResultColumn select c.Key).ToArray());
} }
// Create factory function that can convert a IDataReader record into a POCO // Create factory function that can convert a IDataReader record into a POCO
public Func<IDataReader, T> GetFactory<T>(string key, bool ForceDateTimesToUtc, IDataReader r) public Func<IDataReader, T> GetFactory<T>(string key, bool ForceDateTimesToUtc, IDataReader r)
{ {
lock (PocoFactories) lock (PocoFactories)
{ {
// Have we already created it? // Have we already created it?
if (PocoFactories.TryGetValue(key, out object factory)) if (PocoFactories.TryGetValue(key, out object factory))
return factory as Func<IDataReader, T>; return factory as Func<IDataReader, T>;
lock (m_Converters) lock (m_Converters)
{ {
// Create the method // Create the method
var m = new DynamicMethod("petapoco_factory_" + PocoFactories.Count.ToString(), typeof(T), new Type[] { typeof(IDataReader) }, true); var m = new DynamicMethod("petapoco_factory_" + PocoFactories.Count.ToString(), typeof(T), new Type[] { typeof(IDataReader) }, true);
var il = m.GetILGenerator(); var il = m.GetILGenerator();
// Running under mono? // Running under mono?
int p = (int)Environment.OSVersion.Platform; int p = (int)Environment.OSVersion.Platform;
bool Mono = (p == 4) || (p == 6) || (p == 128); bool Mono = (p == 4) || (p == 6) || (p == 128);
// var poco=new T() // var poco=new T()
il.Emit(OpCodes.Newobj, typeof(T).GetConstructor(Type.EmptyTypes)); il.Emit(OpCodes.Newobj, typeof(T).GetConstructor(Type.EmptyTypes));
// Enumerate all fields generating a set assignment for the column // Enumerate all fields generating a set assignment for the column
for (int i = 0; i < r.FieldCount; i++) for (int i = 0; i < r.FieldCount; i++)
{ {
// Get the PocoColumn for this db column, ignore if not known // Get the PocoColumn for this db column, ignore if not known
if (!Columns.TryGetValue(r.GetName(i), out PocoColumn pc)) if (!Columns.TryGetValue(r.GetName(i), out PocoColumn pc))
continue; continue;
// Get the source type for this column // Get the source type for this column
var srcType = r.GetFieldType(i); var srcType = r.GetFieldType(i);
var dstType = pc.PropertyInfo.PropertyType; var dstType = pc.PropertyInfo.PropertyType;
// "if (!rdr.IsDBNull(i))" // "if (!rdr.IsDBNull(i))"
il.Emit(OpCodes.Ldarg_0); // poco,rdr il.Emit(OpCodes.Ldarg_0); // poco,rdr
il.Emit(OpCodes.Ldc_I4, i); // poco,rdr,i il.Emit(OpCodes.Ldc_I4, i); // poco,rdr,i
il.Emit(OpCodes.Callvirt, fnIsDBNull); // poco,bool il.Emit(OpCodes.Callvirt, fnIsDBNull); // poco,bool
var lblNext = il.DefineLabel(); var lblNext = il.DefineLabel();
il.Emit(OpCodes.Brtrue_S, lblNext); // poco il.Emit(OpCodes.Brtrue_S, lblNext); // poco
il.Emit(OpCodes.Dup); // poco,poco il.Emit(OpCodes.Dup); // poco,poco
// Do we need to install a converter? // Do we need to install a converter?
Func<object, object> converter = null; Func<object, object> converter = null;
// Get converter from the mapper // Get converter from the mapper
if (Database.Mapper != null) if (Database.Mapper != null)
{ {
converter = Mapper.GetValueConverter(pc.PropertyInfo, srcType); converter = Mapper.GetValueConverter(pc.PropertyInfo, srcType);
} }
// Standard DateTime->Utc mapper // Standard DateTime->Utc mapper
if (ForceDateTimesToUtc && converter == null && srcType == typeof(DateTime) && (dstType == typeof(DateTime) || dstType == typeof(DateTime?))) if (ForceDateTimesToUtc && converter == null && srcType == typeof(DateTime) && (dstType == typeof(DateTime) || dstType == typeof(DateTime?)))
{ {
converter = (object src) => new DateTime(((DateTime)src).Ticks, DateTimeKind.Utc); converter = (object src) => new DateTime(((DateTime)src).Ticks, DateTimeKind.Utc);
} }
// Forced type conversion // Forced type conversion
if (converter == null && !dstType.IsAssignableFrom(srcType)) if (converter == null && !dstType.IsAssignableFrom(srcType))
{ {
converter = (object src) => Convert.ChangeType(src, dstType, null); converter = (object src) => Convert.ChangeType(src, dstType, null);
} }
// Fast // Fast
bool Handled = false; bool Handled = false;
if (converter == null) if (converter == null)
{ {
var valuegetter = typeof(IDataRecord).GetMethod("Get" + srcType.Name, new Type[] { typeof(int) }); var valuegetter = typeof(IDataRecord).GetMethod("Get" + srcType.Name, new Type[] { typeof(int) });
if (valuegetter != null if (valuegetter != null
&& valuegetter.ReturnType == srcType && valuegetter.ReturnType == srcType
&& (valuegetter.ReturnType == dstType || valuegetter.ReturnType == Nullable.GetUnderlyingType(dstType))) && (valuegetter.ReturnType == dstType || valuegetter.ReturnType == Nullable.GetUnderlyingType(dstType)))
{ {
il.Emit(OpCodes.Ldarg_0); // *,rdr il.Emit(OpCodes.Ldarg_0); // *,rdr
il.Emit(OpCodes.Ldc_I4, i); // *,rdr,i il.Emit(OpCodes.Ldc_I4, i); // *,rdr,i
il.Emit(OpCodes.Callvirt, valuegetter); // *,value il.Emit(OpCodes.Callvirt, valuegetter); // *,value
// Mono give IL error if we don't explicitly create Nullable instance for the assignment // Mono give IL error if we don't explicitly create Nullable instance for the assignment
if (Mono && Nullable.GetUnderlyingType(dstType) != null) if (Mono && Nullable.GetUnderlyingType(dstType) != null)
{ {
il.Emit(OpCodes.Newobj, dstType.GetConstructor(new Type[] { Nullable.GetUnderlyingType(dstType) })); il.Emit(OpCodes.Newobj, dstType.GetConstructor(new Type[] { Nullable.GetUnderlyingType(dstType) }));
} }
il.Emit(OpCodes.Callvirt, pc.PropertyInfo.GetSetMethod()); // poco il.Emit(OpCodes.Callvirt, pc.PropertyInfo.GetSetMethod()); // poco
Handled = true; Handled = true;
} }
} }
// Not so fast // Not so fast
if (!Handled) if (!Handled)
{ {
// Setup stack for call to converter // Setup stack for call to converter
int converterIndex = -1; int converterIndex = -1;
if (converter != null) if (converter != null)
{ {
// Add the converter // Add the converter
converterIndex = m_Converters.Count; converterIndex = m_Converters.Count;
m_Converters.Add(converter); m_Converters.Add(converter);
// Generate IL to push the converter onto the stack // Generate IL to push the converter onto the stack
il.Emit(OpCodes.Ldsfld, fldConverters); il.Emit(OpCodes.Ldsfld, fldConverters);
il.Emit(OpCodes.Ldc_I4, converterIndex); il.Emit(OpCodes.Ldc_I4, converterIndex);
il.Emit(OpCodes.Callvirt, fnListGetItem); // Converter il.Emit(OpCodes.Callvirt, fnListGetItem); // Converter
} }
// "value = rdr.GetValue(i)" // "value = rdr.GetValue(i)"
il.Emit(OpCodes.Ldarg_0); // *,rdr il.Emit(OpCodes.Ldarg_0); // *,rdr
il.Emit(OpCodes.Ldc_I4, i); // *,rdr,i il.Emit(OpCodes.Ldc_I4, i); // *,rdr,i
il.Emit(OpCodes.Callvirt, fnGetValue); // *,value il.Emit(OpCodes.Callvirt, fnGetValue); // *,value
// Call the converter // Call the converter
if (converter != null) if (converter != null)
il.Emit(OpCodes.Callvirt, fnInvoke); il.Emit(OpCodes.Callvirt, fnInvoke);
// Assign it // Assign it
il.Emit(OpCodes.Unbox_Any, pc.PropertyInfo.PropertyType); // poco,poco,value il.Emit(OpCodes.Unbox_Any, pc.PropertyInfo.PropertyType); // poco,poco,value
il.Emit(OpCodes.Callvirt, pc.PropertyInfo.GetSetMethod()); // poco il.Emit(OpCodes.Callvirt, pc.PropertyInfo.GetSetMethod()); // poco
} }
il.MarkLabel(lblNext); il.MarkLabel(lblNext);
} }
il.Emit(OpCodes.Ret); il.Emit(OpCodes.Ret);
// Cache it, return it // Cache it, return it
var del = (Func<IDataReader, T>)m.CreateDelegate(typeof(Func<IDataReader, T>)); var del = (Func<IDataReader, T>)m.CreateDelegate(typeof(Func<IDataReader, T>));
PocoFactories.Add(key, del); PocoFactories.Add(key, del);
return del; return del;
} }
} }
} }
private static readonly Dictionary<Type, PocoData> m_PocoData = new Dictionary<Type, PocoData>(); private static readonly Dictionary<Type, PocoData> m_PocoData = new Dictionary<Type, PocoData>();
private static readonly List<Func<object, object>> m_Converters = new List<Func<object, object>>(); private static readonly List<Func<object, object>> m_Converters = new List<Func<object, object>>();
private static readonly MethodInfo fnGetValue = typeof(IDataRecord).GetMethod("GetValue", new Type[] { typeof(int) }); private static readonly MethodInfo fnGetValue = typeof(IDataRecord).GetMethod("GetValue", new Type[] { typeof(int) });
private static readonly MethodInfo fnIsDBNull = typeof(IDataRecord).GetMethod("IsDBNull"); private static readonly MethodInfo fnIsDBNull = typeof(IDataRecord).GetMethod("IsDBNull");
private static readonly FieldInfo fldConverters = typeof(PocoData).GetField("m_Converters", BindingFlags.Static | BindingFlags.GetField | BindingFlags.NonPublic); private static readonly FieldInfo fldConverters = typeof(PocoData).GetField("m_Converters", BindingFlags.Static | BindingFlags.GetField | BindingFlags.NonPublic);
private static readonly MethodInfo fnListGetItem = typeof(List<Func<object, object>>).GetProperty("Item").GetGetMethod(); private static readonly MethodInfo fnListGetItem = typeof(List<Func<object, object>>).GetProperty("Item").GetGetMethod();
private static readonly MethodInfo fnInvoke = typeof(Func<object, object>).GetMethod("Invoke"); private static readonly MethodInfo fnInvoke = typeof(Func<object, object>).GetMethod("Invoke");
public string TableName { get; } public string TableName { get; }
public string PrimaryKey { get; } public string PrimaryKey { get; }
...@@ -1266,28 +1266,28 @@ public PocoData(Type t) ...@@ -1266,28 +1266,28 @@ public PocoData(Type t)
public Dictionary<string, PocoColumn> Columns { get; } public Dictionary<string, PocoColumn> Columns { get; }
private readonly Dictionary<string, object> PocoFactories = new Dictionary<string, object>(); private readonly Dictionary<string, object> PocoFactories = new Dictionary<string, object>();
} }
// ShareableConnection represents either a shared connection used by a transaction, // ShareableConnection represents either a shared connection used by a transaction,
// or a one-off connection if not in a transaction. // or a one-off connection if not in a transaction.
// Non-shared connections are disposed // Non-shared connections are disposed
private class ShareableConnection : IDisposable private class ShareableConnection : IDisposable
{ {
public ShareableConnection(Database db) public ShareableConnection(Database db)
{ {
_db = db; _db = db;
_db.OpenSharedConnection(); _db.OpenSharedConnection();
} }
public DbConnection Connection => _db._sharedConnection; public DbConnection Connection => _db._sharedConnection;
private readonly Database _db; private readonly Database _db;
public void Dispose() public void Dispose()
{ {
_db.CloseSharedConnection(); _db.CloseSharedConnection();
} }
} }
// Member variables // Member variables
private readonly string _connectionString; private readonly string _connectionString;
...@@ -1301,43 +1301,43 @@ public void Dispose() ...@@ -1301,43 +1301,43 @@ public void Dispose()
private string _lastSql; private string _lastSql;
private object[] _lastArgs; private object[] _lastArgs;
private string _paramPrefix = "@"; private string _paramPrefix = "@";
} }
// Transaction object helps maintain transaction depth counts // Transaction object helps maintain transaction depth counts
public class Transaction : IDisposable public class Transaction : IDisposable
{ {
public Transaction(Database db) public Transaction(Database db)
{ {
_db = db; _db = db;
_db.BeginTransaction(); _db.BeginTransaction();
} }
public void Complete() public void Complete()
{ {
_db.CompleteTransaction(); _db.CompleteTransaction();
_db = null; _db = null;
} }
public void Dispose() public void Dispose()
{ {
_db?.AbortTransaction(); _db?.AbortTransaction();
} }
private Database _db; private Database _db;
} }
// Simple helper class for building SQL statments // Simple helper class for building SQL statments
public class Sql public class Sql
{ {
public Sql() public Sql()
{ {
} }
public Sql(string sql, params object[] args) public Sql(string sql, params object[] args)
{ {
_sql = sql; _sql = sql;
_args = args; _args = args;
} }
private readonly string _sql; private readonly string _sql;
private readonly object[] _args; private readonly object[] _args;
...@@ -1346,101 +1346,101 @@ public Sql(string sql, params object[] args) ...@@ -1346,101 +1346,101 @@ public Sql(string sql, params object[] args)
private object[] _argsFinal; private object[] _argsFinal;
private void Build() private void Build()
{ {
// already built? // already built?
if (_sqlFinal != null) if (_sqlFinal != null)
return; return;
// Build it // Build it
var sb = new StringBuilder(); var sb = new StringBuilder();
var args = new List<object>(); var args = new List<object>();
Build(sb, args, null); Build(sb, args, null);
_sqlFinal = sb.ToString(); _sqlFinal = sb.ToString();
_argsFinal = args.ToArray(); _argsFinal = args.ToArray();
} }
public string SQL public string SQL
{ {
get get
{ {
Build(); Build();
return _sqlFinal; return _sqlFinal;
} }
} }
public object[] Arguments public object[] Arguments
{ {
get get
{ {
Build(); Build();
return _argsFinal; return _argsFinal;
} }
} }
public Sql Append(Sql sql) public Sql Append(Sql sql)
{ {
if (_rhs != null) if (_rhs != null)
_rhs.Append(sql); _rhs.Append(sql);
else else
_rhs = sql; _rhs = sql;
return this; return this;
} }
public Sql Append(string sql, params object[] args) public Sql Append(string sql, params object[] args)
{ {
return Append(new Sql(sql, args)); return Append(new Sql(sql, args));
} }
public Sql Where(string sql, params object[] args) public Sql Where(string sql, params object[] args)
{ {
return Append(new Sql("WHERE " + sql, args)); return Append(new Sql("WHERE " + sql, args));
} }
public Sql OrderBy(params object[] args) public Sql OrderBy(params object[] args)
{ {
return Append(new Sql("ORDER BY " + String.Join(", ", (from x in args select x.ToString()).ToArray()))); return Append(new Sql("ORDER BY " + String.Join(", ", (from x in args select x.ToString()).ToArray())));
} }
public Sql Select(params object[] args) public Sql Select(params object[] args)
{ {
return Append(new Sql("SELECT " + String.Join(", ", (from x in args select x.ToString()).ToArray()))); return Append(new Sql("SELECT " + String.Join(", ", (from x in args select x.ToString()).ToArray())));
} }
public Sql From(params object[] args) public Sql From(params object[] args)
{ {
return Append(new Sql("FROM " + String.Join(", ", (from x in args select x.ToString()).ToArray()))); return Append(new Sql("FROM " + String.Join(", ", (from x in args select x.ToString()).ToArray())));
} }
private static bool Is(Sql sql, string sqltype) private static bool Is(Sql sql, string sqltype)
{ {
return sql?._sql != null && sql._sql.StartsWith(sqltype, StringComparison.InvariantCultureIgnoreCase); return sql?._sql != null && sql._sql.StartsWith(sqltype, StringComparison.InvariantCultureIgnoreCase);
} }
public void Build(StringBuilder sb, List<object> args, Sql lhs) public void Build(StringBuilder sb, List<object> args, Sql lhs)
{ {
if (!String.IsNullOrEmpty(_sql)) if (!String.IsNullOrEmpty(_sql))
{ {
// Add SQL to the string // Add SQL to the string
if (sb.Length > 0) if (sb.Length > 0)
{ {
sb.Append("\n"); sb.Append("\n");
} }
var sql = Database.ProcessParams(_sql, _args, args); var sql = Database.ProcessParams(_sql, _args, args);
if (Is(lhs, "WHERE ") && Is(this, "WHERE ")) if (Is(lhs, "WHERE ") && Is(this, "WHERE "))
sql = "AND " + sql.Substring(6); sql = "AND " + sql.Substring(6);
if (Is(lhs, "ORDER BY ") && Is(this, "ORDER BY ")) if (Is(lhs, "ORDER BY ") && Is(this, "ORDER BY "))
sql = ", " + sql.Substring(9); sql = ", " + sql.Substring(9);
sb.Append(sql); sb.Append(sql);
} }
// Now do rhs // Now do rhs
_rhs?.Build(sb, args, this); _rhs?.Build(sb, args, this);
} }
} }
} }
#pragma warning restore RCS1023 // Format empty block. #pragma warning restore RCS1023 // Format empty block.
#endif #endif
\ No newline at end of file
...@@ -25,7 +25,7 @@ public async Task TestBasicStringUsageAsync() ...@@ -25,7 +25,7 @@ public async Task TestBasicStringUsageAsync()
[Fact] [Fact]
public async Task TestBasicStringUsageQueryFirstAsync() public async Task TestBasicStringUsageQueryFirstAsync()
{ {
var str = await connection.QueryFirstAsync<string>(new CommandDefinition("select 'abc' as [Value] union all select @txt", new {txt = "def"})).ConfigureAwait(false); var str = await connection.QueryFirstAsync<string>(new CommandDefinition("select 'abc' as [Value] union all select @txt", new { txt = "def" })).ConfigureAwait(false);
Assert.Equal("abc", str); Assert.Equal("abc", str);
} }
...@@ -39,7 +39,7 @@ public async Task TestBasicStringUsageQueryFirstAsyncDynamic() ...@@ -39,7 +39,7 @@ public async Task TestBasicStringUsageQueryFirstAsyncDynamic()
[Fact] [Fact]
public async Task TestBasicStringUsageQueryFirstOrDefaultAsync() public async Task TestBasicStringUsageQueryFirstOrDefaultAsync()
{ {
var str = await connection.QueryFirstOrDefaultAsync<string>(new CommandDefinition("select null as [Value] union all select @txt", new {txt = "def"})).ConfigureAwait(false); var str = await connection.QueryFirstOrDefaultAsync<string>(new CommandDefinition("select null as [Value] union all select @txt", new { txt = "def" })).ConfigureAwait(false);
Assert.Null(str); Assert.Null(str);
} }
...@@ -165,7 +165,8 @@ public async Task TestMultiMapWithSplitAsync() ...@@ -165,7 +165,8 @@ public async Task TestMultiMapWithSplitAsync()
public async Task TestMultiMapArbitraryWithSplitAsync() public async Task TestMultiMapArbitraryWithSplitAsync()
{ {
const string sql = "select 1 as id, 'abc' as name, 2 as id, 'def' as name"; const string sql = "select 1 as id, 'abc' as name, 2 as id, 'def' as name";
var productQuery = await connection.QueryAsync<Product>(sql, new[] { typeof(Product), typeof(Category) }, (objects) => { var productQuery = await connection.QueryAsync<Product>(sql, new[] { typeof(Product), typeof(Category) }, (objects) =>
{
var prod = (Product)objects[0]; var prod = (Product)objects[0];
prod.Category = (Category)objects[1]; prod.Category = (Category)objects[1];
return prod; return prod;
...@@ -393,7 +394,8 @@ public void AssertNoCacheWorksForQueryMultiple() ...@@ -393,7 +394,8 @@ public void AssertNoCacheWorksForQueryMultiple()
const int a = 123, b = 456; const int a = 123, b = 456;
var cmdDef = new CommandDefinition("select @a; select @b;", new var cmdDef = new CommandDefinition("select @a; select @b;", new
{ {
a, b a,
b
}, commandType: CommandType.Text, flags: CommandFlags.NoCache); }, commandType: CommandType.Text, flags: CommandFlags.NoCache);
int c, d; int c, d;
...@@ -784,7 +786,7 @@ public async Task Issue157_ClosedReaderAsync() ...@@ -784,7 +786,7 @@ public async Task Issue157_ClosedReaderAsync()
var args = new { x = 42 }; var args = new { x = 42 };
const string sql = "select 123 as [A], 'abc' as [B] where @x=42"; const string sql = "select 123 as [A], 'abc' as [B] where @x=42";
var row = (await connection.QueryAsync<SomeType>(new CommandDefinition( var row = (await connection.QueryAsync<SomeType>(new CommandDefinition(
sql, args, flags:CommandFlags.None)).ConfigureAwait(false)).Single(); sql, args, flags: CommandFlags.None)).ConfigureAwait(false)).Single();
Assert.NotNull(row); Assert.NotNull(row);
Assert.Equal(123, row.A); Assert.Equal(123, row.A);
Assert.Equal("abc", row.B); Assert.Equal("abc", row.B);
...@@ -828,4 +830,4 @@ public async Task Issue563_QueryAsyncShouldThrowException() ...@@ -828,4 +830,4 @@ public async Task Issue563_QueryAsyncShouldThrowException()
catch (SqlException ex) when (ex.Message == "after select") { /* swallow only this */ } catch (SqlException ex) when (ex.Message == "after select") { /* swallow only this */ }
} }
} }
} }
\ No newline at end of file
...@@ -91,9 +91,9 @@ union all ...@@ -91,9 +91,9 @@ union all
var col = reader.GetOrdinal("Type"); var col = reader.GetOrdinal("Type");
var splitOn = reader.GetOrdinal("Id"); var splitOn = reader.GetOrdinal("Id");
var toFoo = reader.GetRowParser<DiscriminatedWithMultiMapping_BaseType>(typeof(DiscriminatedWithMultiMapping_Foo),0, splitOn); var toFoo = reader.GetRowParser<DiscriminatedWithMultiMapping_BaseType>(typeof(DiscriminatedWithMultiMapping_Foo), 0, splitOn);
var toBar = reader.GetRowParser<DiscriminatedWithMultiMapping_BaseType>(typeof(DiscriminatedWithMultiMapping_Bar),0, splitOn); var toBar = reader.GetRowParser<DiscriminatedWithMultiMapping_BaseType>(typeof(DiscriminatedWithMultiMapping_Bar), 0, splitOn);
var toHaz = reader.GetRowParser<HazNameId>(typeof(HazNameId),splitOn, reader.FieldCount - splitOn); var toHaz = reader.GetRowParser<HazNameId>(typeof(HazNameId), splitOn, reader.FieldCount - splitOn);
do do
{ {
...@@ -102,10 +102,10 @@ union all ...@@ -102,10 +102,10 @@ union all
{ {
case 1: case 1:
obj = toFoo(reader); obj = toFoo(reader);
break; break;
case 2: case 2:
obj = toBar(reader); obj = toBar(reader);
break; break;
} }
Assert.NotNull(obj); Assert.NotNull(obj);
...@@ -165,4 +165,4 @@ private class DiscriminatedWithMultiMapping_Bar : DiscriminatedWithMultiMapping_ ...@@ -165,4 +165,4 @@ private class DiscriminatedWithMultiMapping_Bar : DiscriminatedWithMultiMapping_
public override int Type => 2; public override int Type => 2;
} }
} }
} }
\ No newline at end of file
...@@ -6,7 +6,7 @@ namespace Dapper.Tests ...@@ -6,7 +6,7 @@ namespace Dapper.Tests
public class NullTests : TestBase public class NullTests : TestBase
{ {
[Fact] [Fact]
public void TestNullableDefault() public void TestNullableDefault()
{ {
TestNullable(false); TestNullable(false);
} }
...@@ -17,10 +17,10 @@ public void TestNullableApplyNulls() ...@@ -17,10 +17,10 @@ public void TestNullableApplyNulls()
TestNullable(true); TestNullable(true);
} }
private void TestNullable(bool applyNulls) private void TestNullable(bool applyNulls)
{ {
bool oldSetting = SqlMapper.Settings.ApplyNullValues; bool oldSetting = SqlMapper.Settings.ApplyNullValues;
try try
{ {
SqlMapper.Settings.ApplyNullValues = applyNulls; SqlMapper.Settings.ApplyNullValues = applyNulls;
SqlMapper.PurgeQueryCache(); SqlMapper.PurgeQueryCache();
...@@ -51,7 +51,7 @@ private void TestNullable(bool applyNulls) ...@@ -51,7 +51,7 @@ private void TestNullable(bool applyNulls)
Assert.Equal(AnEnum.B, obj.D); Assert.Equal(AnEnum.B, obj.D);
Assert.Null(obj.E); Assert.Null(obj.E);
} }
else else
{ {
Assert.Equal(2, obj.A); Assert.Equal(2, obj.A);
Assert.Equal(2, obj.B); Assert.Equal(2, obj.B);
...@@ -59,7 +59,8 @@ private void TestNullable(bool applyNulls) ...@@ -59,7 +59,8 @@ private void TestNullable(bool applyNulls)
Assert.Equal(AnEnum.B, obj.D); Assert.Equal(AnEnum.B, obj.D);
Assert.Equal(AnEnum.B, obj.E); Assert.Equal(AnEnum.B, obj.E);
} }
} finally }
finally
{ {
SqlMapper.Settings.ApplyNullValues = oldSetting; SqlMapper.Settings.ApplyNullValues = oldSetting;
} }
...@@ -67,14 +68,14 @@ private void TestNullable(bool applyNulls) ...@@ -67,14 +68,14 @@ private void TestNullable(bool applyNulls)
private class NullTestClass private class NullTestClass
{ {
public int Id { get; set; } public int Id { get; set; }
public int A { get; set; } public int A { get; set; }
public int? B { get; set; } public int? B { get; set; }
public string C { get; set; } public string C { get; set; }
public AnEnum D { get; set; } public AnEnum D { get; set; }
public AnEnum? E { get; set; } public AnEnum? E { get; set; }
public NullTestClass() public NullTestClass()
{ {
A = 2; A = 2;
B = 2; B = 2;
......
...@@ -445,7 +445,7 @@ public void SO29533765_DataTableParametersViaDynamicParameters() ...@@ -445,7 +445,7 @@ public void SO29533765_DataTableParametersViaDynamicParameters()
connection.Execute("create type MyTVPType as table (id int)"); connection.Execute("create type MyTVPType as table (id int)");
connection.Execute("create proc #DataTableParameters @ids MyTVPType readonly as select count(1) from @ids"); connection.Execute("create proc #DataTableParameters @ids MyTVPType readonly as select count(1) from @ids");
var table = new DataTable { TableName="MyTVPType", Columns = { { "id", typeof(int) } }, Rows = { { 1 }, { 2 }, { 3 } } }; var table = new DataTable { TableName = "MyTVPType", Columns = { { "id", typeof(int) } }, Rows = { { 1 }, { 2 }, { 3 } } };
table.SetTypeName(table.TableName); // per SO29533765 table.SetTypeName(table.TableName); // per SO29533765
IDictionary<string, object> args = new Dictionary<string, object> IDictionary<string, object> args = new Dictionary<string, object>
{ {
...@@ -1060,8 +1060,9 @@ public void SO25297173_DynamicIn() ...@@ -1060,8 +1060,9 @@ public void SO25297173_DynamicIn()
insert @table values(6); insert @table values(6);
insert @table values(7); insert @table values(7);
SELECT value FROM @table WHERE value IN @myIds"; SELECT value FROM @table WHERE value IN @myIds";
var queryParams = new Dictionary<string, object> { var queryParams = new Dictionary<string, object>
["myIds"] = new [] { 5, 6 } {
["myIds"] = new[] { 5, 6 }
}; };
var dynamicParams = new DynamicParameters(queryParams); var dynamicParams = new DynamicParameters(queryParams);
......
...@@ -11,7 +11,7 @@ public EntityFrameworkTests() ...@@ -11,7 +11,7 @@ public EntityFrameworkTests()
{ {
EntityFramework.Handlers.Register(); EntityFramework.Handlers.Register();
} }
[Fact] [Fact]
public void Issue570_DbGeo_HasValues() public void Issue570_DbGeo_HasValues()
{ {
......
...@@ -44,4 +44,4 @@ public void Issue178_Firebird() ...@@ -44,4 +44,4 @@ public void Issue178_Firebird()
} }
} }
} }
} }
\ No newline at end of file
...@@ -60,4 +60,4 @@ public void TestNoDefaultConstructorBinary() ...@@ -60,4 +60,4 @@ public void TestNoDefaultConstructorBinary()
} }
} }
} }
#endif #endif
\ No newline at end of file
...@@ -269,4 +269,4 @@ public async void Issue457_NullParameterValues_MultiAsync_Named() ...@@ -269,4 +269,4 @@ public async void Issue457_NullParameterValues_MultiAsync_Named()
} }
} }
} }
#endif #endif
\ No newline at end of file
...@@ -53,4 +53,4 @@ public class AuthorCE ...@@ -53,4 +53,4 @@ public class AuthorCE
} }
} }
} }
#endif #endif
\ No newline at end of file
...@@ -145,7 +145,7 @@ public void Issue524_QueryMultiple_Cast() ...@@ -145,7 +145,7 @@ public void Issue524_QueryMultiple_Cast()
Assert.Equal(42, connection.QuerySingle<int>("select cast(42 as bigint)")); Assert.Equal(42, connection.QuerySingle<int>("select cast(42 as bigint)"));
// using multi-reader API // using multi-reader API
using(var reader = connection.QueryMultiple("select cast(42 as bigint); select cast(42 as bigint)")) using (var reader = connection.QueryMultiple("select cast(42 as bigint); select cast(42 as bigint)"))
{ {
Assert.Equal(42, reader.Read<int>().Single()); Assert.Equal(42, reader.Read<int>().Single());
Assert.Equal(42, reader.ReadSingle<int>()); Assert.Equal(42, reader.ReadSingle<int>());
......
...@@ -377,9 +377,9 @@ private RatingValueHandler() ...@@ -377,9 +377,9 @@ private RatingValueHandler()
public override RatingValue Parse(object value) public override RatingValue Parse(object value)
{ {
if (value is Int32) if (value is int)
{ {
return new RatingValue() { Value = (Int32)value }; return new RatingValue() { Value = (int)value };
} }
throw new FormatException("Invalid conversion to RatingValue"); throw new FormatException("Invalid conversion to RatingValue");
...@@ -395,13 +395,13 @@ public override void SetValue(IDbDataParameter parameter, RatingValue value) ...@@ -395,13 +395,13 @@ public override void SetValue(IDbDataParameter parameter, RatingValue value)
public class RatingValue public class RatingValue
{ {
public Int32 Value { get; set; } public int Value { get; set; }
// ... some other properties etc ... // ... some other properties etc ...
} }
public class MyResult public class MyResult
{ {
public String CategoryName { get; set; } public string CategoryName { get; set; }
public RatingValue CategoryRating { get; set; } public RatingValue CategoryRating { get; set; }
} }
...@@ -424,7 +424,7 @@ public void SO24740733_TestCustomValueSingleColumn() ...@@ -424,7 +424,7 @@ public void SO24740733_TestCustomValueSingleColumn()
Assert.Equal(200, foo.Value); Assert.Equal(200, foo.Value);
} }
public class StringListTypeHandler : SqlMapper.TypeHandler<List<String>> public class StringListTypeHandler : SqlMapper.TypeHandler<List<string>>
{ {
private StringListTypeHandler() private StringListTypeHandler()
{ {
...@@ -434,18 +434,18 @@ private StringListTypeHandler() ...@@ -434,18 +434,18 @@ private StringListTypeHandler()
//Just a simple List<string> type handler implementation //Just a simple List<string> type handler implementation
public override void SetValue(IDbDataParameter parameter, List<string> value) public override void SetValue(IDbDataParameter parameter, List<string> value)
{ {
parameter.Value = String.Join(",", value); parameter.Value = string.Join(",", value);
} }
public override List<string> Parse(object value) public override List<string> Parse(object value)
{ {
return ((value as String) ?? "").Split(',').ToList(); return ((value as string) ?? "").Split(',').ToList();
} }
} }
public class MyObjectWithStringList public class MyObjectWithStringList
{ {
public List<String> Names { get; set; } public List<string> Names { get; set; }
} }
[Fact] [Fact]
......
...@@ -5,6 +5,7 @@ VisualStudioVersion = 15.0.26730.8 ...@@ -5,6 +5,7 @@ VisualStudioVersion = 15.0.26730.8
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A34907DF-958A-4E4C-8491-84CF303FD13E}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A34907DF-958A-4E4C-8491-84CF303FD13E}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
appveyor.yml = appveyor.yml appveyor.yml = appveyor.yml
build.ps1 = build.ps1 build.ps1 = build.ps1
build.sh = build.sh build.sh = build.sh
......
...@@ -61,7 +61,6 @@ public void AddParameter(IDbCommand command, string name) ...@@ -61,7 +61,6 @@ public void AddParameter(IDbCommand command, string name)
{ {
param = command.CreateParameter(); param = command.CreateParameter();
param.ParameterName = name; param.ParameterName = name;
} }
else else
{ {
......
...@@ -91,7 +91,7 @@ public ConstructorInfo FindConstructor(string[] names, Type[] types) ...@@ -91,7 +91,7 @@ public ConstructorInfo FindConstructor(string[] names, Type[] types)
int i = 0; int i = 0;
for (; i < ctorParameters.Length; i++) 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; break;
if (types[i] == typeof(byte[]) && ctorParameters[i].ParameterType.FullName == SqlMapper.LinqBinary) if (types[i] == typeof(byte[]) && ctorParameters[i].ParameterType.FullName == SqlMapper.LinqBinary)
continue; continue;
...@@ -152,13 +152,13 @@ public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor, ...@@ -152,13 +152,13 @@ public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor,
/// <returns>Mapping implementation</returns> /// <returns>Mapping implementation</returns>
public SqlMapper.IMemberMap GetMember(string columnName) public SqlMapper.IMemberMap GetMember(string columnName)
{ {
var property = Properties.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.Ordinal)) var property = Properties.Find(p => string.Equals(p.Name, columnName, StringComparison.Ordinal))
?? Properties.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase)); ?? Properties.Find(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase));
if (property == null && MatchNamesWithUnderscores) if (property == null && MatchNamesWithUnderscores)
{ {
property = Properties.FirstOrDefault(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.Ordinal)) property = Properties.Find(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.Ordinal))
?? Properties.FirstOrDefault(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.OrdinalIgnoreCase)); ?? Properties.Find(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.OrdinalIgnoreCase));
} }
if (property != null) if (property != null)
...@@ -169,20 +169,20 @@ public SqlMapper.IMemberMap GetMember(string columnName) ...@@ -169,20 +169,20 @@ public SqlMapper.IMemberMap GetMember(string columnName)
// preference order is: // 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 // 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)) var field = _fields.Find(p => string.Equals(p.Name, columnName, StringComparison.Ordinal))
?? _fields.FirstOrDefault(p => string.Equals(p.Name, backingFieldName, StringComparison.Ordinal)) ?? _fields.Find(p => string.Equals(p.Name, backingFieldName, StringComparison.Ordinal))
?? _fields.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase)) ?? _fields.Find(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase))
?? _fields.FirstOrDefault(p => string.Equals(p.Name, backingFieldName, StringComparison.OrdinalIgnoreCase)); ?? _fields.Find(p => string.Equals(p.Name, backingFieldName, StringComparison.OrdinalIgnoreCase));
if (field == null && MatchNamesWithUnderscores) if (field == null && MatchNamesWithUnderscores)
{ {
var effectiveColumnName = columnName.Replace("_", ""); var effectiveColumnName = columnName.Replace("_", "");
backingFieldName = "<" +effectiveColumnName + ">k__BackingField"; backingFieldName = "<" + effectiveColumnName + ">k__BackingField";
field = _fields.FirstOrDefault(p => string.Equals(p.Name, effectiveColumnName, StringComparison.Ordinal)) field = _fields.Find(p => string.Equals(p.Name, effectiveColumnName, StringComparison.Ordinal))
?? _fields.FirstOrDefault(p => string.Equals(p.Name, backingFieldName, StringComparison.Ordinal)) ?? _fields.Find(p => string.Equals(p.Name, backingFieldName, StringComparison.Ordinal))
?? _fields.FirstOrDefault(p => string.Equals(p.Name, effectiveColumnName, StringComparison.OrdinalIgnoreCase)) ?? _fields.Find(p => string.Equals(p.Name, effectiveColumnName, StringComparison.OrdinalIgnoreCase))
?? _fields.FirstOrDefault(p => string.Equals(p.Name, backingFieldName, StringComparison.OrdinalIgnoreCase)); ?? _fields.Find(p => string.Equals(p.Name, backingFieldName, StringComparison.OrdinalIgnoreCase));
} }
if (field != null) if (field != null)
......
...@@ -394,7 +394,7 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express ...@@ -394,7 +394,7 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express
} }
while (diving != null); while (diving != null);
var dynamicParamName = string.Join(string.Empty, names.ToArray()); var dynamicParamName = string.Concat(names.ToArray());
// Before we get all emitty... // Before we get all emitty...
var lookup = string.Join("|", names.ToArray()); var lookup = string.Join("|", names.ToArray());
......
...@@ -407,7 +407,7 @@ private static async Task<IEnumerable<T>> QueryAsync<T>(this IDbConnection cnn, ...@@ -407,7 +407,7 @@ private static async Task<IEnumerable<T>> QueryAsync<T>(this IDbConnection cnn,
object val = func(reader); object val = func(reader);
if (val == null || val is T) if (val == null || val is T)
{ {
buffer.Add((T) val); buffer.Add((T)val);
} }
else else
{ {
...@@ -564,7 +564,8 @@ private static async Task<int> ExecuteMultiImplAsync(IDbConnection cnn, CommandD ...@@ -564,7 +564,8 @@ private static async Task<int> ExecuteMultiImplAsync(IDbConnection cnn, CommandD
masterSql = cmd.CommandText; masterSql = cmd.CommandText;
var identity = new Identity(command.CommandText, cmd.CommandType, cnn, null, obj.GetType(), null); var identity = new Identity(command.CommandText, cmd.CommandType, cnn, null, obj.GetType(), null);
info = GetCacheInfo(identity, obj, command.AddToCache); info = GetCacheInfo(identity, obj, command.AddToCache);
} else if(pending.Count >= MAX_PENDING) }
else if (pending.Count >= MAX_PENDING)
{ {
var recycled = pending.Dequeue(); var recycled = pending.Dequeue();
total += await recycled.Task.ConfigureAwait(false); total += await recycled.Task.ConfigureAwait(false);
...@@ -955,15 +956,18 @@ private static async Task<IEnumerable<TReturn>> MultiMapAsync<TReturn>(this IDbC ...@@ -955,15 +956,18 @@ private static async Task<IEnumerable<TReturn>> MultiMapAsync<TReturn>(this IDbC
var identity = new Identity(command.CommandText, command.CommandType, cnn, types[0], param?.GetType(), types); var identity = new Identity(command.CommandText, command.CommandType, cnn, types[0], param?.GetType(), types);
var info = GetCacheInfo(identity, param, command.AddToCache); var info = GetCacheInfo(identity, param, command.AddToCache);
bool wasClosed = cnn.State == ConnectionState.Closed; bool wasClosed = cnn.State == ConnectionState.Closed;
try { try
{
if (wasClosed) await ((DbConnection)cnn).OpenAsync().ConfigureAwait(false); if (wasClosed) await ((DbConnection)cnn).OpenAsync().ConfigureAwait(false);
using (var cmd = (DbCommand)command.SetupCommand(cnn, info.ParamReader)) using (var cmd = (DbCommand)command.SetupCommand(cnn, info.ParamReader))
using (var reader = await ExecuteReaderWithFlagsFallbackAsync(cmd, wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult, command.CancellationToken).ConfigureAwait(false)) { using (var reader = await ExecuteReaderWithFlagsFallbackAsync(cmd, wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult, command.CancellationToken).ConfigureAwait(false))
{
var results = MultiMapImpl(null, default(CommandDefinition), types, map, splitOn, reader, identity, true); var results = MultiMapImpl(null, default(CommandDefinition), types, map, splitOn, reader, identity, true);
return command.Buffered ? results.ToList() : results; return command.Buffered ? results.ToList() : results;
} }
} }
finally { finally
{
if (wasClosed) cnn.Close(); if (wasClosed) cnn.Close();
} }
} }
...@@ -1027,8 +1031,9 @@ public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn, ...@@ -1027,8 +1031,9 @@ public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn,
if (!reader.IsClosed) if (!reader.IsClosed)
{ {
try { cmd.Cancel(); } try { cmd.Cancel(); }
catch { /* don't spoil the existing exception */ catch
} { /* don't spoil the existing exception */
}
} }
reader.Dispose(); reader.Dispose();
} }
......
...@@ -169,7 +169,7 @@ private T ReadRow<T>(Type type, Row row) ...@@ -169,7 +169,7 @@ private T ReadRow<T>(Type type, Row row)
IsConsumed = true; IsConsumed = true;
T result = default(T); T result = default(T);
if(reader.Read() && reader.FieldCount != 0) if (reader.Read() && reader.FieldCount != 0)
{ {
var typedIdentity = identity.ForGrid(type, gridIndex); var typedIdentity = identity.ForGrid(type, gridIndex);
CacheInfo cache = GetCacheInfo(typedIdentity, null, addToCache); CacheInfo cache = GetCacheInfo(typedIdentity, null, addToCache);
...@@ -194,7 +194,7 @@ private T ReadRow<T>(Type type, Row row) ...@@ -194,7 +194,7 @@ private T ReadRow<T>(Type type, Row row)
if ((row & Row.Single) != 0 && reader.Read()) ThrowMultipleRows(row); if ((row & Row.Single) != 0 && reader.Read()) ThrowMultipleRows(row);
while (reader.Read()) { /* ignore subsequent rows */ } 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); ThrowZeroRows(row);
} }
...@@ -372,9 +372,12 @@ private IEnumerable<T> ReadDeferred<T>(int index, Func<IDataReader, object> dese ...@@ -372,9 +372,12 @@ private IEnumerable<T> ReadDeferred<T>(int index, Func<IDataReader, object> dese
while (index == gridIndex && reader.Read()) while (index == gridIndex && reader.Read())
{ {
object val = deserializer(reader); object val = deserializer(reader);
if (val == null || val is T) { if (val == null || val is T)
{
yield return (T)val; yield return (T)val;
} else { }
else
{
yield return (T)Convert.ChangeType(val, convertToType, CultureInfo.InvariantCulture); yield return (T)Convert.ChangeType(val, convertToType, CultureInfo.InvariantCulture);
} }
} }
...@@ -439,4 +442,4 @@ public void Dispose() ...@@ -439,4 +442,4 @@ public void Dispose()
} }
} }
} }
} }
\ No newline at end of file
...@@ -171,45 +171,45 @@ public static int GetCachedSQLCount() ...@@ -171,45 +171,45 @@ public static int GetCachedSQLCount()
static SqlMapper() static SqlMapper()
{ {
typeMap = new Dictionary<Type, DbType> typeMap = new Dictionary<Type, DbType>
{ {
[typeof(byte)] = DbType.Byte, [typeof(byte)] = DbType.Byte,
[typeof(sbyte)] = DbType.SByte, [typeof(sbyte)] = DbType.SByte,
[typeof(short)] = DbType.Int16, [typeof(short)] = DbType.Int16,
[typeof(ushort)] = DbType.UInt16, [typeof(ushort)] = DbType.UInt16,
[typeof(int)] = DbType.Int32, [typeof(int)] = DbType.Int32,
[typeof(uint)] = DbType.UInt32, [typeof(uint)] = DbType.UInt32,
[typeof(long)] = DbType.Int64, [typeof(long)] = DbType.Int64,
[typeof(ulong)] = DbType.UInt64, [typeof(ulong)] = DbType.UInt64,
[typeof(float)] = DbType.Single, [typeof(float)] = DbType.Single,
[typeof(double)] = DbType.Double, [typeof(double)] = DbType.Double,
[typeof(decimal)] = DbType.Decimal, [typeof(decimal)] = DbType.Decimal,
[typeof(bool)] = DbType.Boolean, [typeof(bool)] = DbType.Boolean,
[typeof(string)] = DbType.String, [typeof(string)] = DbType.String,
[typeof(char)] = DbType.StringFixedLength, [typeof(char)] = DbType.StringFixedLength,
[typeof(Guid)] = DbType.Guid, [typeof(Guid)] = DbType.Guid,
[typeof(DateTime)] = DbType.DateTime, [typeof(DateTime)] = DbType.DateTime,
[typeof(DateTimeOffset)] = DbType.DateTimeOffset, [typeof(DateTimeOffset)] = DbType.DateTimeOffset,
[typeof(TimeSpan)] = DbType.Time, [typeof(TimeSpan)] = DbType.Time,
[typeof(byte[])] = DbType.Binary, [typeof(byte[])] = DbType.Binary,
[typeof(byte?)] = DbType.Byte, [typeof(byte?)] = DbType.Byte,
[typeof(sbyte?)] = DbType.SByte, [typeof(sbyte?)] = DbType.SByte,
[typeof(short?)] = DbType.Int16, [typeof(short?)] = DbType.Int16,
[typeof(ushort?)] = DbType.UInt16, [typeof(ushort?)] = DbType.UInt16,
[typeof(int?)] = DbType.Int32, [typeof(int?)] = DbType.Int32,
[typeof(uint?)] = DbType.UInt32, [typeof(uint?)] = DbType.UInt32,
[typeof(long?)] = DbType.Int64, [typeof(long?)] = DbType.Int64,
[typeof(ulong?)] = DbType.UInt64, [typeof(ulong?)] = DbType.UInt64,
[typeof(float?)] = DbType.Single, [typeof(float?)] = DbType.Single,
[typeof(double?)] = DbType.Double, [typeof(double?)] = DbType.Double,
[typeof(decimal?)] = DbType.Decimal, [typeof(decimal?)] = DbType.Decimal,
[typeof(bool?)] = DbType.Boolean, [typeof(bool?)] = DbType.Boolean,
[typeof(char?)] = DbType.StringFixedLength, [typeof(char?)] = DbType.StringFixedLength,
[typeof(Guid?)] = DbType.Guid, [typeof(Guid?)] = DbType.Guid,
[typeof(DateTime?)] = DbType.DateTime, [typeof(DateTime?)] = DbType.DateTime,
[typeof(DateTimeOffset?)] = DbType.DateTimeOffset, [typeof(DateTimeOffset?)] = DbType.DateTimeOffset,
[typeof(TimeSpan?)] = DbType.Time, [typeof(TimeSpan?)] = DbType.Time,
[typeof(object)] = DbType.Object [typeof(object)] = DbType.Object
}; };
ResetTypeHandlers(false); ResetTypeHandlers(false);
} }
...@@ -327,7 +327,7 @@ public static void AddTypeHandlerImpl(Type type, ITypeHandler handler, bool clon ...@@ -327,7 +327,7 @@ public static void AddTypeHandlerImpl(Type type, ITypeHandler handler, bool clon
else else
{ {
newCopy[type] = handler; newCopy[type] = handler;
if(secondary != null) newCopy[secondary] = handler; if (secondary != null) newCopy[secondary] = handler;
} }
typeHandlers = newCopy; typeHandlers = newCopy;
} }
...@@ -413,7 +413,7 @@ public static DbType LookupDbType(Type type, string name, bool demand, out IType ...@@ -413,7 +413,7 @@ public static DbType LookupDbType(Type type, string name, bool demand, out IType
return DbType.Object; return DbType.Object;
} }
#endif #endif
if(demand) if (demand)
throw new NotSupportedException($"The member {name} of type {type.FullName} cannot be used as a parameter value"); throw new NotSupportedException($"The member {name} of type {type.FullName} cannot be used as a parameter value");
return DbType.Object; return DbType.Object;
} }
...@@ -509,7 +509,7 @@ private static IEnumerable GetMultiExec(object param) ...@@ -509,7 +509,7 @@ private static IEnumerable GetMultiExec(object param)
&& !(param is string && !(param is string
|| param is IEnumerable<KeyValuePair<string, object>> || param is IEnumerable<KeyValuePair<string, object>>
|| param is IDynamicParameters) || param is IDynamicParameters)
) ? (IEnumerable) param : null; ) ? (IEnumerable)param : null;
} }
private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition command) private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition command)
...@@ -520,7 +520,7 @@ private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition com ...@@ -520,7 +520,7 @@ private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition com
CacheInfo info = null; CacheInfo info = null;
if (multiExec != null) if (multiExec != null)
{ {
if((command.Flags & CommandFlags.Pipelined) != 0) if ((command.Flags & CommandFlags.Pipelined) != 0)
{ {
// this includes all the code for concurrent/overlapped query // this includes all the code for concurrent/overlapped query
return ExecuteMultiImplAsync(cnn, command, multiExec).Result; return ExecuteMultiImplAsync(cnn, command, multiExec).Result;
...@@ -553,7 +553,8 @@ private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition com ...@@ -553,7 +553,8 @@ private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition com
} }
} }
command.OnCompleted(); command.OnCompleted();
} finally }
finally
{ {
if (wasClosed) cnn.Close(); if (wasClosed) cnn.Close();
} }
...@@ -844,7 +845,7 @@ public static IEnumerable<object> Query(this IDbConnection cnn, Type type, strin ...@@ -844,7 +845,7 @@ public static IEnumerable<object> Query(this IDbConnection cnn, Type type, strin
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)); 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<object>(cnn, Row.First, ref command, type); return QueryRowImpl<object>(cnn, Row.First, ref command, type);
} }
...@@ -1089,7 +1090,7 @@ private static IEnumerable<T> QueryImpl<T>(this IDbConnection cnn, CommandDefini ...@@ -1089,7 +1090,7 @@ private static IEnumerable<T> QueryImpl<T>(this IDbConnection cnn, CommandDefini
if (reader.FieldCount == 0) //https://code.google.com/p/dapper-dot-net/issues/detail?id=57 if (reader.FieldCount == 0) //https://code.google.com/p/dapper-dot-net/issues/detail?id=57
yield break; yield break;
tuple = info.Deserializer = new DeserializerState(hash, GetDeserializer(effectiveType, reader, 0, -1, false)); 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; var func = tuple.Func;
...@@ -1097,9 +1098,12 @@ private static IEnumerable<T> QueryImpl<T>(this IDbConnection cnn, CommandDefini ...@@ -1097,9 +1098,12 @@ private static IEnumerable<T> QueryImpl<T>(this IDbConnection cnn, CommandDefini
while (reader.Read()) while (reader.Read())
{ {
object val = func(reader); object val = func(reader);
if (val == null || val is T) { if (val == null || val is T)
{
yield return (T)val; yield return (T)val;
} else { }
else
{
yield return (T)Convert.ChangeType(val, convertToType, CultureInfo.InvariantCulture); yield return (T)Convert.ChangeType(val, convertToType, CultureInfo.InvariantCulture);
} }
} }
...@@ -1425,10 +1429,10 @@ public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string ...@@ -1425,10 +1429,10 @@ public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string
int hash = GetColumnHash(reader); int hash = GetColumnHash(reader);
if ((deserializer = cinfo.Deserializer).Func == null || (otherDeserializers = cinfo.OtherDeserializers) == null || hash != deserializer.Hash) 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]); deserializer = cinfo.Deserializer = new DeserializerState(hash, deserializers[0]);
otherDeserializers = cinfo.OtherDeserializers = deserializers.Skip(1).ToArray(); otherDeserializers = cinfo.OtherDeserializers = deserializers.Skip(1).ToArray();
if(command.AddToCache) SetQueryCache(identity, cinfo); if (command.AddToCache) SetQueryCache(identity, cinfo);
} }
Func<IDataReader, TReturn> mapIt = GenerateMapper<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(deserializer.Func, otherDeserializers, map); Func<IDataReader, TReturn> mapIt = GenerateMapper<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(deserializer.Func, otherDeserializers, map);
...@@ -1571,7 +1575,7 @@ private static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn ...@@ -1571,7 +1575,7 @@ private static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn
{ {
var deserializers = new List<Func<IDataReader, object>>(); var deserializers = new List<Func<IDataReader, object>>();
var splits = splitOn.Split(',').Select(s => s.Trim()).ToArray(); var splits = splitOn.Split(',').Select(s => s.Trim()).ToArray();
bool isMultiSplit = splits.Length > 1; bool isMultiSplit = splits.Length > 1;
if (types[0] == typeof(object)) if (types[0] == typeof(object))
{ {
// we go left to right for dynamic multi-mapping so that the madness of TestMultiMappingVariations // we go left to right for dynamic multi-mapping so that the madness of TestMultiMappingVariations
...@@ -1607,7 +1611,7 @@ private static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn ...@@ -1607,7 +1611,7 @@ private static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn
for (var typeIdx = types.Length - 1; typeIdx >= 0; --typeIdx) for (var typeIdx = types.Length - 1; typeIdx >= 0; --typeIdx)
{ {
var type = types[typeIdx]; var type = types[typeIdx];
if (type == typeof (DontMap)) if (type == typeof(DontMap))
{ {
continue; continue;
} }
...@@ -1729,7 +1733,7 @@ private static void PassByPosition(IDbCommand cmd) ...@@ -1729,7 +1733,7 @@ private static void PassByPosition(IDbCommand cmd)
Dictionary<string, IDbDataParameter> parameters = new Dictionary<string, IDbDataParameter>(StringComparer.Ordinal); Dictionary<string, IDbDataParameter> parameters = new Dictionary<string, IDbDataParameter>(StringComparer.Ordinal);
foreach(IDbDataParameter param in cmd.Parameters) foreach (IDbDataParameter param in cmd.Parameters)
{ {
if (!string.IsNullOrEmpty(param.ParameterName)) parameters[param.ParameterName] = param; if (!string.IsNullOrEmpty(param.ParameterName)) parameters[param.ParameterName] = param;
} }
...@@ -1923,7 +1927,7 @@ public static IDbDataParameter FindOrAddParameter(IDataParameterCollection param ...@@ -1923,7 +1927,7 @@ public static IDbDataParameter FindOrAddParameter(IDataParameterCollection param
internal static int GetListPaddingExtraCount(int count) internal static int GetListPaddingExtraCount(int count)
{ {
switch(count) switch (count)
{ {
case 0: case 0:
case 1: case 1:
...@@ -1995,7 +1999,7 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj ...@@ -1995,7 +1999,7 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
{ {
if (++count == 1) // first item: fetch some type info 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"); throw new NotSupportedException("The first item in a list-expansion cannot be null");
} }
...@@ -2042,7 +2046,7 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj ...@@ -2042,7 +2046,7 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
count++; count++;
var padParam = command.CreateParameter(); var padParam = command.CreateParameter();
padParam.ParameterName = namePrefix + count.ToString(); padParam.ParameterName = namePrefix + count.ToString();
if(isString) padParam.Size = DbString.DefaultLength; if (isString) padParam.Size = DbString.DefaultLength;
padParam.DbType = dbType; padParam.DbType = dbType;
padParam.Value = lastValue; padParam.Value = lastValue;
command.Parameters.Add(padParam); command.Parameters.Add(padParam);
...@@ -2050,7 +2054,7 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj ...@@ -2050,7 +2054,7 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
} }
} }
if(viaSplit) if (viaSplit)
{ {
// already done // already done
} }
...@@ -2064,8 +2068,8 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj ...@@ -2064,8 +2068,8 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
var variableName = match.Groups[1].Value; var variableName = match.Groups[1].Value;
if (match.Groups[2].Success) if (match.Groups[2].Success)
{ {
// looks like an optimize hint; leave it alone! // looks like an optimize hint; leave it alone!
return match.Value; return match.Value;
} }
else else
{ {
...@@ -2084,8 +2088,8 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj ...@@ -2084,8 +2088,8 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
var variableName = match.Groups[1].Value; var variableName = match.Groups[1].Value;
if (match.Groups[2].Success) if (match.Groups[2].Success)
{ {
// looks like an optimize hint; expand it // looks like an optimize hint; expand it
var suffix = match.Groups[2].Value; var suffix = match.Groups[2].Value;
var sb = GetStringBuilder().Append(variableName).Append(1).Append(suffix); var sb = GetStringBuilder().Append(variableName).Append(1).Append(suffix);
for (int i = 2; i <= count; i++) for (int i = 2; i <= count; i++)
...@@ -2097,7 +2101,7 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj ...@@ -2097,7 +2101,7 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
else else
{ {
var sb = GetStringBuilder().Append('(').Append(variableName); var sb = GetStringBuilder().Append('(').Append(variableName);
if(!byPosition) sb.Append(1); if (!byPosition) sb.Append(1);
for (int i = 2; i <= count; i++) for (int i = 2; i <= count; i++)
{ {
sb.Append(',').Append(variableName); sb.Append(',').Append(variableName);
...@@ -2165,11 +2169,11 @@ private static bool TryStringSplit(ref IEnumerable list, int splitAt, string nam ...@@ -2165,11 +2169,11 @@ private static bool TryStringSplit(ref IEnumerable list, int splitAt, string nam
string val; string val;
using (var iter = typed.GetEnumerator()) using (var iter = typed.GetEnumerator())
{ {
if(iter.MoveNext()) if (iter.MoveNext())
{ {
var sb = GetStringBuilder(); var sb = GetStringBuilder();
append(sb, iter.Current); append(sb, iter.Current);
while(iter.MoveNext()) while (iter.MoveNext())
{ {
append(sb.Append(','), iter.Current); append(sb.Append(','), iter.Current);
} }
...@@ -2293,13 +2297,13 @@ public static string Format(object value) ...@@ -2293,13 +2297,13 @@ public static string Format(object value)
return ((decimal)value).ToString(CultureInfo.InvariantCulture); return ((decimal)value).ToString(CultureInfo.InvariantCulture);
default: default:
var multiExec = GetMultiExec(value); var multiExec = GetMultiExec(value);
if(multiExec != null) if (multiExec != null)
{ {
StringBuilder sb = null; StringBuilder sb = null;
bool first = true; bool first = true;
foreach (object subval in multiExec) foreach (object subval in multiExec)
{ {
if(first) if (first)
{ {
sb = GetStringBuilder().Append('('); sb = GetStringBuilder().Append('(');
first = false; first = false;
...@@ -2310,7 +2314,7 @@ public static string Format(object value) ...@@ -2310,7 +2314,7 @@ public static string Format(object value)
} }
sb.Append(Format(subval)); sb.Append(Format(subval));
} }
if(first) if (first)
{ {
return "(select null where 1=0)"; return "(select null where 1=0)";
} }
...@@ -2346,10 +2350,10 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql) ...@@ -2346,10 +2350,10 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
var matches = literalTokens.Matches(sql); var matches = literalTokens.Matches(sql);
var found = new HashSet<string>(StringComparer.Ordinal); var found = new HashSet<string>(StringComparer.Ordinal);
List<LiteralToken> list = new List<LiteralToken>(matches.Count); List<LiteralToken> list = new List<LiteralToken>(matches.Count);
foreach(Match match in matches) foreach (Match match in matches)
{ {
string token = match.Value; string token = match.Value;
if(found.Add(match.Value)) if (found.Add(match.Value))
{ {
list.Add(new LiteralToken(token, match.Groups[1].Value)); list.Add(new LiteralToken(token, match.Groups[1].Value));
} }
...@@ -2372,13 +2376,13 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) ...@@ -2372,13 +2376,13 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
{ {
var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance); var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
var result = new List<IMemberMap>(names.Length); var result = new List<IMemberMap>(names.Length);
for(int i = 0; i < names.Length; i++) for (int i = 0; i < names.Length; i++)
{ {
FieldInfo field = null; FieldInfo field = null;
string name = "Item" + (i + 1).ToString(CultureInfo.InvariantCulture); string name = "Item" + (i + 1).ToString(CultureInfo.InvariantCulture);
foreach(var test in fields) foreach (var test in fields)
{ {
if(test.Name == name) if (test.Name == name)
{ {
field = test; field = test;
break; break;
...@@ -2427,7 +2431,7 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) ...@@ -2427,7 +2431,7 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
var allTypeProps = type.GetProperties(); var allTypeProps = type.GetProperties();
var propsList = new List<PropertyInfo>(allTypeProps.Length); var propsList = new List<PropertyInfo>(allTypeProps.Length);
for(int i = 0; i < allTypeProps.Length; ++i) for (int i = 0; i < allTypeProps.Length; ++i)
{ {
var p = allTypeProps[i]; var p = allTypeProps[i];
if (p.GetIndexParameters().Length == 0) if (p.GetIndexParameters().Length == 0)
...@@ -2451,14 +2455,15 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) ...@@ -2451,14 +2455,15 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
break; break;
} }
} }
if(ok) if (ok)
{ {
// pre-sorted; the reflection gods have smiled upon us // pre-sorted; the reflection gods have smiled upon us
props = propsList; props = propsList;
} }
else { // might still all be accounted for; check the hard way else
var positionByName = new Dictionary<string,int>(StringComparer.OrdinalIgnoreCase); { // might still all be accounted for; check the hard way
foreach(var param in ctorParams) var positionByName = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
foreach (var param in ctorParams)
{ {
positionByName[param.Name] = param.Position; positionByName[param.Name] = param.Position;
} }
...@@ -2478,12 +2483,12 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) ...@@ -2478,12 +2483,12 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
if (ok) if (ok)
{ {
props = propsList.ToArray(); props = propsList.ToArray();
Array.Sort(positions, (PropertyInfo[]) props); Array.Sort(positions, (PropertyInfo[])props);
} }
} }
} }
} }
if(props == null) if (props == null)
{ {
propsList.Sort(new PropertyInfoByNameComparer()); propsList.Sort(new PropertyInfoByNameComparer());
props = propsList; props = propsList;
...@@ -2573,9 +2578,9 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) ...@@ -2573,9 +2578,9 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
var nullType = Nullable.GetUnderlyingType(propType); var nullType = Nullable.GetUnderlyingType(propType);
bool callSanitize = false; bool callSanitize = false;
if((nullType ?? propType).IsEnum()) if ((nullType ?? propType).IsEnum())
{ {
if(nullType != null) if (nullType != null)
{ {
// Nullable<SomeEnum>; we want to box as the underlying type; that's just *hard*; for // Nullable<SomeEnum>; we want to box as the underlying type; that's just *hard*; for
// simplicity, box as Nullable<SomeEnum> and call SanitizeParameterValue // simplicity, box as Nullable<SomeEnum> and call SanitizeParameterValue
...@@ -2609,7 +2614,8 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) ...@@ -2609,7 +2614,8 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
il.EmitCall(OpCodes.Call, typeof(SqlMapper).GetMethod(nameof(SanitizeParameterValue)), null); il.EmitCall(OpCodes.Call, typeof(SqlMapper).GetMethod(nameof(SanitizeParameterValue)), null);
// stack is [parameters] [[parameters]] [parameter] [parameter] [boxed-value] // stack is [parameters] [[parameters]] [parameter] [parameter] [boxed-value]
} }
} else }
else
{ {
checkForNull = true; // if not a value-type, need to check checkForNull = true; // if not a value-type, need to check
} }
...@@ -2699,7 +2705,7 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) ...@@ -2699,7 +2705,7 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
// stack is currently [parameters] // stack is currently [parameters]
il.Emit(OpCodes.Pop); // stack is now empty il.Emit(OpCodes.Pop); // stack is now empty
if(literals.Count != 0 && propsList != null) if (literals.Count != 0 && propsList != null)
{ {
il.Emit(OpCodes.Ldarg_0); // command il.Emit(OpCodes.Ldarg_0); // command
il.Emit(OpCodes.Ldarg_0); // command, command il.Emit(OpCodes.Ldarg_0); // command, command
...@@ -2712,13 +2718,13 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) ...@@ -2712,13 +2718,13 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
// find the best member, preferring case-sensitive // find the best member, preferring case-sensitive
PropertyInfo exact = null, fallback = null; PropertyInfo exact = null, fallback = null;
string huntName = literal.Member; string huntName = literal.Member;
for(int i = 0; i < propsList.Count; i++) for (int i = 0; i < propsList.Count; i++)
{ {
string thisName = propsList[i].Name; string thisName = propsList[i].Name;
if(string.Equals(thisName, huntName, StringComparison.OrdinalIgnoreCase)) if (string.Equals(thisName, huntName, StringComparison.OrdinalIgnoreCase))
{ {
fallback = propsList[i]; fallback = propsList[i];
if(string.Equals(thisName, huntName, StringComparison.Ordinal)) if (string.Equals(thisName, huntName, StringComparison.Ordinal))
{ {
exact = fallback; exact = fallback;
break; break;
...@@ -2727,7 +2733,7 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) ...@@ -2727,7 +2733,7 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
} }
var prop = exact ?? fallback; var prop = exact ?? fallback;
if(prop != null) if (prop != null)
{ {
il.Emit(OpCodes.Ldstr, literal.Token); il.Emit(OpCodes.Ldstr, literal.Token);
il.Emit(OpCodes.Ldloc_0); // command, sql, typed parameter il.Emit(OpCodes.Ldloc_0); // command, sql, typed parameter
...@@ -2846,7 +2852,7 @@ private static T ExecuteScalarImpl<T>(IDbConnection cnn, ref CommandDefinition c ...@@ -2846,7 +2852,7 @@ private static T ExecuteScalarImpl<T>(IDbConnection cnn, ref CommandDefinition c
{ {
cmd = command.SetupCommand(cnn, paramReader); cmd = command.SetupCommand(cnn, paramReader);
if (wasClosed) cnn.Open(); if (wasClosed) cnn.Open();
result =cmd.ExecuteScalar(); result = cmd.ExecuteScalar();
command.OnCompleted(); command.OnCompleted();
} }
finally finally
...@@ -2922,7 +2928,7 @@ private static IDataReader ExecuteReaderImpl(IDbConnection cnn, ref CommandDefin ...@@ -2922,7 +2928,7 @@ private static IDataReader ExecuteReaderImpl(IDbConnection cnn, ref CommandDefin
return r => return r =>
{ {
var val = r.GetValue(index); var val = r.GetValue(index);
if(val is float || val is double || val is decimal) if (val is float || val is double || val is decimal)
{ {
val = Convert.ChangeType(val, Enum.GetUnderlyingType(effectiveType), CultureInfo.InvariantCulture); val = Convert.ChangeType(val, Enum.GetUnderlyingType(effectiveType), CultureInfo.InvariantCulture);
} }
...@@ -2995,7 +3001,7 @@ public static ITypeMap GetTypeMap(Type type) ...@@ -2995,7 +3001,7 @@ public static ITypeMap GetTypeMap(Type type)
if (map == null) if (map == null)
{ {
map = TypeMapProvider( type ); map = TypeMapProvider(type);
_typeMaps[type] = map; _typeMaps[type] = map;
} }
} }
...@@ -3119,9 +3125,9 @@ private static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, Lo ...@@ -3119,9 +3125,9 @@ private static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, Lo
if (explicitConstr != null) if (explicitConstr != null)
{ {
var consPs = explicitConstr.GetParameters(); var consPs = explicitConstr.GetParameters();
foreach(var p in consPs) foreach (var p in consPs)
{ {
if(!p.ParameterType.IsValueType()) if (!p.ParameterType.IsValueType())
{ {
il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Ldnull);
} }
...@@ -3181,7 +3187,7 @@ private static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, Lo ...@@ -3181,7 +3187,7 @@ private static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, Lo
il.Emit(OpCodes.Ldloc_1);// [target] il.Emit(OpCodes.Ldloc_1);// [target]
} }
var members = IsValueTuple(type) ? GetValueTupleMembers(type, names) :((specializedConstructor != null var members = IsValueTuple(type) ? GetValueTupleMembers(type, names) : ((specializedConstructor != null
? names.Select(n => typeMap.GetConstructorParameter(specializedConstructor, n)) ? names.Select(n => typeMap.GetConstructorParameter(specializedConstructor, n))
: names.Select(n => typeMap.GetMember(n))).ToList()); : names.Select(n => typeMap.GetMember(n))).ToList());
...@@ -3229,7 +3235,7 @@ private static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, Lo ...@@ -3229,7 +3235,7 @@ private static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, Lo
if (unboxType.IsEnum()) if (unboxType.IsEnum())
{ {
Type numericType = Enum.GetUnderlyingType(unboxType); Type numericType = Enum.GetUnderlyingType(unboxType);
if(colType == typeof(string)) if (colType == typeof(string))
{ {
if (enumDeclareLocal == -1) if (enumDeclareLocal == -1)
{ {
...@@ -3273,7 +3279,7 @@ private static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, Lo ...@@ -3273,7 +3279,7 @@ private static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, Lo
} }
else else
{ {
il.Emit(OpCodes.Unbox_Any, unboxType); // stack is now [target][target][typed-value] il.Emit(OpCodes.Unbox_Any, unboxType); // stack is now [target][target][typed-value]
} }
} }
else else
...@@ -3318,7 +3324,7 @@ private static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, Lo ...@@ -3318,7 +3324,7 @@ private static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, Lo
il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Ldnull);
} }
} }
else if(applyNullSetting && (!memberType.IsValueType() || Nullable.GetUnderlyingType(memberType) != null)) else if (applyNullSetting && (!memberType.IsValueType() || Nullable.GetUnderlyingType(memberType) != null))
{ {
il.Emit(OpCodes.Pop); // stack is now [target][target] il.Emit(OpCodes.Pop); // stack is now [target][target]
// can load a null with this value // can load a null with this value
...@@ -3402,11 +3408,11 @@ private static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, Lo ...@@ -3402,11 +3408,11 @@ private static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, Lo
private static void FlexibleConvertBoxedFromHeadOfStack(ILGenerator il, Type from, Type to, Type via) private static void FlexibleConvertBoxedFromHeadOfStack(ILGenerator il, Type from, Type to, Type via)
{ {
MethodInfo op; MethodInfo op;
if(from == (via ?? to)) if (from == (via ?? to))
{ {
il.Emit(OpCodes.Unbox_Any, to); // stack is now [target][target][typed-value] il.Emit(OpCodes.Unbox_Any, to); // stack is now [target][target][typed-value]
} }
else if ((op = GetOperator(from,to)) != null) else if ((op = GetOperator(from, to)) != null)
{ {
// this is handy for things like decimal <===> double // this is handy for things like decimal <===> double
il.Emit(OpCodes.Unbox_Any, from); // stack is now [target][target][data-typed-value] il.Emit(OpCodes.Unbox_Any, from); // stack is now [target][target][data-typed-value]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment