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