Commit ad0a2622 authored by Nick Craver's avatar Nick Craver

Contrib, Rainbow, EntityFramework & SqlBuilder: code cleanup

parent bc8468f4
This diff is collapsed.
......@@ -17,11 +17,8 @@
using System.Threading;
#endif
#pragma warning disable 1573, 1591 // xml comments
namespace Dapper.Contrib.Extensions
{
public static partial class SqlMapperExtensions
{
// ReSharper disable once MemberCanBePrivate.Global
......@@ -45,13 +42,15 @@ public interface ITableNameMapper
private static readonly ConcurrentDictionary<RuntimeTypeHandle, string> GetQueries = new ConcurrentDictionary<RuntimeTypeHandle, string>();
private static readonly ConcurrentDictionary<RuntimeTypeHandle, string> TypeTableName = new ConcurrentDictionary<RuntimeTypeHandle, string>();
private static readonly Dictionary<string, ISqlAdapter> AdapterDictionary = new Dictionary<string, ISqlAdapter> {
{"sqlconnection", new SqlServerAdapter()},
{"sqlceconnection", new SqlCeServerAdapter()},
{"npgsqlconnection", new PostgresAdapter()},
{"sqliteconnection", new SQLiteAdapter()},
{"mysqlconnection", new MySqlAdapter()},
};
private static readonly Dictionary<string, ISqlAdapter> AdapterDictionary
= new Dictionary<string, ISqlAdapter>
{
{"sqlconnection", new SqlServerAdapter()},
{"sqlceconnection", new SqlCeServerAdapter()},
{"npgsqlconnection", new PostgresAdapter()},
{"sqliteconnection", new SQLiteAdapter()},
{"mysqlconnection", new MySqlAdapter()},
};
private static List<PropertyInfo> ComputedPropertiesCache(Type type)
{
......@@ -137,6 +136,8 @@ private static bool IsWriteable(PropertyInfo pi)
/// <typeparam name="T">Interface or type to create and populate</typeparam>
/// <param name="connection">Open SqlConnection</param>
/// <param name="id">Id of the entity to get, must be marked with [Key] attribute</param>
/// <param name="transaction">The transaction to run under, null (the defualt) if none</param>
/// <param name="commandTimeout">Number of seconds before command execution timeout</param>
/// <returns>Entity of T</returns>
public static T Get<T>(this IDbConnection connection, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
{
......@@ -198,6 +199,8 @@ private static bool IsWriteable(PropertyInfo pi)
/// </summary>
/// <typeparam name="T">Interface or type to create and populate</typeparam>
/// <param name="connection">Open SqlConnection</param>
/// <param name="transaction">The transaction to run under, null (the defualt) if none</param>
/// <param name="commandTimeout">Number of seconds before command execution timeout</param>
/// <returns>Entity of T</returns>
public static IEnumerable<T> GetAll<T>(this IDbConnection connection, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
{
......@@ -282,6 +285,8 @@ private static string GetTableName(Type type)
/// </summary>
/// <param name="connection">Open SqlConnection</param>
/// <param name="entityToInsert">Entity to insert, can be list of entities</param>
/// <param name="transaction">The transaction to run under, null (the defualt) if none</param>
/// <param name="commandTimeout">Number of seconds before command execution timeout</param>
/// <returns>Identity of inserted entity, or number of inserted rows if inserting a list</returns>
public static long Insert<T>(this IDbConnection connection, T entityToInsert, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
{
......@@ -346,6 +351,8 @@ private static string GetTableName(Type type)
/// <typeparam name="T">Type to be updated</typeparam>
/// <param name="connection">Open SqlConnection</param>
/// <param name="entityToUpdate">Entity to be updated</param>
/// <param name="transaction">The transaction to run under, null (the defualt) if none</param>
/// <param name="commandTimeout">Number of seconds before command execution timeout</param>
/// <returns>true if updated, false if not found or not modified (tracked entities)</returns>
public static bool Update<T>(this IDbConnection connection, T entityToUpdate, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
{
......@@ -402,6 +409,8 @@ private static string GetTableName(Type type)
/// <typeparam name="T">Type of entity</typeparam>
/// <param name="connection">Open SqlConnection</param>
/// <param name="entityToDelete">Entity to delete</param>
/// <param name="transaction">The transaction to run under, null (the defualt) if none</param>
/// <param name="commandTimeout">Number of seconds before command execution timeout</param>
/// <returns>true if deleted, false if not found</returns>
public static bool Delete<T>(this IDbConnection connection, T entityToDelete, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
{
......@@ -442,6 +451,8 @@ private static string GetTableName(Type type)
/// </summary>
/// <typeparam name="T">Type of entity</typeparam>
/// <param name="connection">Open SqlConnection</param>
/// <param name="transaction">The transaction to run under, null (the defualt) if none</param>
/// <param name="commandTimeout">Number of seconds before command execution timeout</param>
/// <returns>true if deleted, false if none found</returns>
public static bool DeleteAll<T>(this IDbConnection connection, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
{
......@@ -666,7 +677,7 @@ public class ComputedAttribute : Attribute
public partial interface ISqlAdapter
{
int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, String tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert);
int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert);
//new methods for issue #336
void AppendColumnName(StringBuilder sb, string columnName);
......@@ -675,7 +686,7 @@ public partial interface ISqlAdapter
public partial class SqlServerAdapter : ISqlAdapter
{
public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, String tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert)
public int Insert(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 = connection.QueryMultiple(cmd, entityToInsert, transaction, commandTimeout);
......@@ -706,7 +717,7 @@ public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName)
public partial class SqlCeServerAdapter : ISqlAdapter
{
public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, String tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert)
public int Insert(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})";
connection.Execute(cmd, entityToInsert, transaction, commandTimeout);
......@@ -737,7 +748,7 @@ public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName)
public partial class MySqlAdapter : ISqlAdapter
{
public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, String tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert)
public int Insert(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})";
connection.Execute(cmd, entityToInsert, transaction, commandTimeout);
......@@ -768,7 +779,7 @@ public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName)
public partial class PostgresAdapter : ISqlAdapter
{
public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, String tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert)
public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert)
{
var sb = new StringBuilder();
sb.AppendFormat("insert into {0} ({1}) values ({2})", tableName, columnList, parameterList);
......
......@@ -33,9 +33,10 @@ public override void SetValue(IDbDataParameter parameter, DbGeography value)
parsed = SqlGeography.STGeomFromWKB(new SqlBytes(value.AsBinary()), value.CoordinateSystemId);
}
parameter.Value = parsed ?? DBNull.Value;
if (parameter is SqlParameter)
var sqlParameter = parameter as SqlParameter;
if (sqlParameter != null)
{
((SqlParameter)parameter).UdtTypeName = "geography";
sqlParameter.UdtTypeName = "geography";
}
}
/// <summary>
......
......@@ -10,7 +10,7 @@ namespace Dapper.EntityFramework
/// <summary>
/// Type-handler for the DbGeometry spatial type
/// </summary>
public class DbGeometryHandler : Dapper.SqlMapper.TypeHandler<DbGeometry>
public class DbGeometryHandler : SqlMapper.TypeHandler<DbGeometry>
{
/// <summary>
/// Create a new handler instance
......
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace SqlServerTypes
{
/// <summary>
/// Utility methods related to CLR Types for SQL Server
/// </summary>
internal class Utilities
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr LoadLibrary(string libname);
/// <summary>
/// Loads the required native assemblies for the current architecture (x86 or x64)
/// </summary>
/// <param name="rootApplicationPath">
/// Root path of the current application. Use Server.MapPath(".") for ASP.NET applications
/// and AppDomain.CurrentDomain.BaseDirectory for desktop applications.
/// </param>
public static void LoadNativeAssemblies(string rootApplicationPath)
{
var nativeBinaryPath = IntPtr.Size > 4
? Path.Combine(rootApplicationPath, @"SqlServerTypes\x64\")
: Path.Combine(rootApplicationPath, @"SqlServerTypes\x86\");
LoadNativeAssembly(nativeBinaryPath, "msvcr100.dll");
LoadNativeAssembly(nativeBinaryPath, "SqlServerSpatial110.dll");
}
private static void LoadNativeAssembly(string nativeBinaryPath, string assemblyName)
{
var path = Path.Combine(nativeBinaryPath, assemblyName);
var ptr = LoadLibrary(path);
if (ptr == IntPtr.Zero)
{
throw new Exception(string.Format(
"Error loading {0} (ErrorCode: {1})",
assemblyName,
Marshal.GetLastWin32Error()));
}
}
}
}
\ No newline at end of file
<html lang="en-US">
<head>
<meta charset="utf-8" />
<title>Microsoft.SqlServer.Types</title>
<style>
body {
background: #fff;
color: #505050;
margin: 20px;
}
#main {
background: #efefef;
padding: 5px 30px;
}
</style>
</head>
<body>
<div id="main">
<h1>Action required to load native assemblies</h1>
<p>
To deploy an application that uses spatial data types to a machine that does not have 'System CLR Types for SQL Server' installed you also need to deploy the native assembly SqlServerSpatial110.dll. Both x86 (32 bit) and x64 (64 bit) versions of this assembly have been added to your project under the SqlServerTypes\x86 and SqlServerTypes\x64 subdirectories. The native assembly msvcr100.dll is also included in case the C++ runtime is not installed.
</p>
<p>
You need to add code to load the correct one of these assemblies at runtime (depending on the current architecture).
</p>
<h2>ASP.NET applications</h2>
<p>
For ASP.NET applications, add the following line of code to the Application_Start method in Global.asax.cs:
<pre> SqlServerTypes.Utilities.LoadNativeAssemblies(Server.MapPath("~/bin"));</pre>
</p>
<h2>Desktop applications</h2>
<p>
For desktop applications, add the following line of code to run before any spatial operations are performed:
<pre> SqlServerTypes.Utilities.LoadNativeAssemblies(AppDomain.CurrentDomain.BaseDirectory);</pre>
</p>
</div>
</body>
</html>
\ No newline at end of file
......@@ -161,8 +161,8 @@ public static TDatabase Init(DbConnection connection, int commandTimeout)
internal void InitDatabase(DbConnection connection, int commandTimeout)
{
this._connection = connection;
this._commandTimeout = commandTimeout;
_connection = connection;
_commandTimeout = commandTimeout;
if (tableConstructor == null)
{
tableConstructor = CreateTableConstructorForTable();
......@@ -204,13 +204,7 @@ protected Action<TDatabase> CreateTableConstructor(params Type[] tableTypes)
var il = dm.GetILGenerator();
var setters = GetType().GetProperties()
.Where(
#if COREFX
p => p.PropertyType.GetTypeInfo().IsGenericType && tableTypes.Contains(p.PropertyType.GetGenericTypeDefinition())
#else
p => p.PropertyType.IsGenericType && tableTypes.Contains(p.PropertyType.GetGenericTypeDefinition())
#endif
)
.Where(p => p.PropertyType.IsGenericType() && tableTypes.Contains(p.PropertyType.GetGenericTypeDefinition()))
.Select(p => Tuple.Create(
p.GetSetMethod(true),
p.PropertyType.GetConstructor(new[] { typeof(TDatabase), typeof(string) }),
......@@ -286,48 +280,48 @@ private bool TableExists(string name)
}
var builder = new StringBuilder("select 1 from INFORMATION_SCHEMA.TABLES where ");
if (!String.IsNullOrEmpty(schemaName)) builder.Append("TABLE_SCHEMA = @schemaName AND ");
if (!string.IsNullOrEmpty(schemaName)) builder.Append("TABLE_SCHEMA = @schemaName AND ");
builder.Append("TABLE_NAME = @name");
return _connection.Query(builder.ToString(), new { schemaName, name }, transaction: _transaction).Count() == 1;
return _connection.Query(builder.ToString(), new { schemaName, name }, _transaction).Count() == 1;
}
public int Execute(string sql, dynamic param = null)
{
return SqlMapper.Execute(_connection, sql, param as object, _transaction, commandTimeout: this._commandTimeout);
return _connection.Execute(sql, param as object, _transaction, _commandTimeout);
}
public IEnumerable<T> Query<T>(string sql, dynamic param = null, bool buffered = true)
{
return SqlMapper.Query<T>(_connection, sql, param as object, _transaction, buffered, _commandTimeout);
return _connection.Query<T>(sql, param as object, _transaction, buffered, _commandTimeout);
}
public IEnumerable<TReturn> Query<TFirst, TSecond, TReturn>(string sql, Func<TFirst, TSecond, TReturn> map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null)
{
return SqlMapper.Query(_connection, sql, map, param as object, transaction, buffered, splitOn);
return _connection.Query(sql, map, param as object, transaction, buffered, splitOn);
}
public IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TReturn>(string sql, Func<TFirst, TSecond, TThird, TReturn> map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null)
{
return SqlMapper.Query(_connection, sql, map, param as object, transaction, buffered, splitOn);
return _connection.Query(sql, map, param as object, transaction, buffered, splitOn);
}
public IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TReturn>(string sql, Func<TFirst, TSecond, TThird, TFourth, TReturn> map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null)
{
return SqlMapper.Query(_connection, sql, map, param as object, transaction, buffered, splitOn);
return _connection.Query(sql, map, param as object, transaction, buffered, splitOn);
}
public IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TFifth, TReturn>(string sql, Func<TFirst, TSecond, TThird, TFourth, TFifth, TReturn> map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null)
{
return SqlMapper.Query(_connection, sql, map, param as object, transaction, buffered, splitOn);
return _connection.Query(sql, map, param as object, transaction, buffered, splitOn);
}
public IEnumerable<dynamic> Query(string sql, dynamic param = null, bool buffered = true)
{
return SqlMapper.Query(_connection, sql, param as object, _transaction, buffered);
return _connection.Query(sql, param as object, _transaction, buffered);
}
public Dapper.SqlMapper.GridReader QueryMultiple(string sql, dynamic param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
public SqlMapper.GridReader QueryMultiple(string sql, dynamic param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
return SqlMapper.QueryMultiple(_connection, sql, param, transaction, commandTimeout, commandType);
}
......
......@@ -68,17 +68,20 @@ static List<PropertyInfo> RelevantProperties()
).ToList();
}
// This is used by IL, ReSharper is wrong.
// ReSharper disable UnusedMember.Local
private static bool AreEqual<U>(U first, U second)
{
if (first == null && second == null) return true;
if (first == null) return false;
return first.Equals(second);
}
}
// ReSharper restore UnusedMember.Local
private static Func<T, T, List<Change>> GenerateDiffer()
{
var dm = new DynamicMethod("DoDiff", typeof(List<Change>), new Type[] { typeof(T), typeof(T) }, true);
var dm = new DynamicMethod("DoDiff", typeof(List<Change>), new[] { typeof(T), typeof(T) }, true);
var il = dm.GetILGenerator();
// change list
......@@ -198,4 +201,3 @@ private static bool AreEqual<U>(U first, U second)
}
}
}
......@@ -6,8 +6,8 @@ namespace Dapper
{
public class SqlBuilder
{
Dictionary<string, Clauses> data = new Dictionary<string, Clauses>();
int seq;
private readonly Dictionary<string, Clauses> _data = new Dictionary<string, Clauses>();
private int _seq;
class Clause
{
......@@ -18,15 +18,15 @@ class Clause
class Clauses : List<Clause>
{
string joiner;
string prefix;
string postfix;
private readonly string _joiner;
private readonly string _prefix;
private readonly string _postfix;
public Clauses(string joiner, string prefix = "", string postfix = "")
{
this.joiner = joiner;
this.prefix = prefix;
this.postfix = postfix;
_joiner = joiner;
_prefix = prefix;
_postfix = postfix;
}
public string ResolveClauses(DynamicParameters p)
......@@ -36,8 +36,8 @@ public string ResolveClauses(DynamicParameters p)
p.AddDynamicParams(item.Parameters);
}
return this.Any(a => a.IsInclusive)
? prefix +
string.Join(joiner,
? _prefix +
string.Join(_joiner,
this.Where(a => !a.IsInclusive)
.Select(c => c.Sql)
.Union(new[]
......@@ -45,46 +45,45 @@ public string ResolveClauses(DynamicParameters p)
" ( " +
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;
}).ToArray()) + _postfix
: _prefix + string.Join(_joiner, this.Select(c => c.Sql).ToArray()) + _postfix;
}
}
public class Template
{
readonly string sql;
readonly SqlBuilder builder;
readonly object initParams;
int dataSeq = -1; // Unresolved
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)
{
this.initParams = parameters;
this.sql = sql;
this.builder = builder;
_initParams = parameters;
_sql = sql;
_builder = builder;
}
static Regex regex =
new System.Text.RegularExpressions.Regex(@"\/\*\*.+\*\*\/", System.Text.RegularExpressions.RegexOptions.Compiled | System.Text.RegularExpressions.RegexOptions.Multiline);
private static readonly Regex _regex = new Regex(@"\/\*\*.+\*\*\/", RegexOptions.Compiled | RegexOptions.Multiline);
void ResolveSql()
{
if (dataSeq != builder.seq)
if (_dataSeq != _builder._seq)
{
DynamicParameters p = new DynamicParameters(initParams);
DynamicParameters p = new DynamicParameters(_initParams);
rawSql = sql;
rawSql = _sql;
foreach (var pair in builder.data)
foreach (var pair in _builder._data)
{
rawSql = rawSql.Replace("/**" + pair.Key + "**/", pair.Value.ResolveClauses(p));
}
parameters = p;
// replace all that is left with empty
rawSql = regex.Replace(rawSql, "");
rawSql = _regex.Replace(rawSql, "");
dataSeq = builder.seq;
_dataSeq = _builder._seq;
}
}
......@@ -95,8 +94,6 @@ void ResolveSql()
public object Parameters { get { ResolveSql(); return parameters; } }
}
public SqlBuilder() { }
public Template AddTemplate(string sql, dynamic parameters = null)
{
return new Template(this, sql, parameters);
......@@ -105,13 +102,13 @@ public Template AddTemplate(string sql, dynamic parameters = null)
protected void AddClause(string name, string sql, object parameters, string joiner, string prefix = "", string postfix = "", bool isInclusive = false)
{
Clauses clauses;
if (!data.TryGetValue(name, out clauses))
if (!_data.TryGetValue(name, out clauses))
{
clauses = new Clauses(joiner, prefix, postfix);
data[name] = clauses;
_data[name] = clauses;
}
clauses.Add(new Clause { Sql = sql, Parameters = parameters, IsInclusive = isInclusive });
seq++;
_seq++;
}
public SqlBuilder Intersect(string sql, dynamic parameters = null)
......
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CE/@EntryIndexedValue">CE</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SQ/@EntryIndexedValue">SQ</s:String></wpf:ResourceDictionary>
\ No newline at end of file
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SQ/@EntryIndexedValue">SQ</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SQL/@EntryIndexedValue">SQL</s:String></wpf:ResourceDictionary>
\ No newline at end of file
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