Permalink
Browse files

Upped dapper to 1.8

Broke SqlBuilder to another assembly
Added Dapper.Rainbow (minimal ORM)
Changed nuget to distribute DLLs
  • Loading branch information...
1 parent 4d1d028 commit c9160c13fb45eb512f66524825612397aa3728ba @SamSaffron SamSaffron committed Jan 12, 2012
View
4 Dapper NET35/Dapper NET35.csproj
@@ -8,8 +8,8 @@
<ProjectGuid>{B26305D8-3A89-4D68-A981-9BBF378B81FA}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>Dapper_NET35</RootNamespace>
- <AssemblyName>Dapper NET35</AssemblyName>
+ <RootNamespace>Dapper</RootNamespace>
+ <AssemblyName>Dapper</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
View
4 Dapper.Contrib.Tests/Dapper.Contrib.Tests.csproj
@@ -65,6 +65,10 @@
<Project>{C2FC4DF5-C8D1-4EA8-8E0C-85A3793EB0BB}</Project>
<Name>Dapper.Contrib</Name>
</ProjectReference>
+ <ProjectReference Include="..\Dapper.SqlBuilder\Dapper.SqlBuilder.csproj">
+ <Project>{BF782EF1-2B0F-42FA-9DD0-928454A94C6D}</Project>
+ <Name>Dapper.SqlBuilder</Name>
+ </ProjectReference>
<ProjectReference Include="..\Dapper\Dapper.csproj">
<Project>{DAF737E1-05B5-4189-A5AA-DAC6233B64D7}</Project>
<Name>Dapper</Name>
View
1 Dapper.Contrib.Tests/Tests.cs
@@ -6,6 +6,7 @@
using Dapper.Contrib.Extensions;
using System.Collections.Generic;
using System;
+using Dapper;
namespace Dapper.Contrib.Tests
View
151 Dapper.Contrib/SqlMapperExtensions.cs
@@ -440,155 +440,4 @@ public class KeyAttribute : Attribute
{
}
- public class SqlBuilder
- {
-
- Dictionary<string, Clauses> data = new Dictionary<string, Clauses>();
- int seq;
-
- class Clause
- {
- public string Sql { get; set; }
- public object Parameters { get; set; }
- }
-
- class Clauses : List<Clause>
- {
- string joiner;
- string prefix;
- string postfix;
-
- public Clauses(string joiner, string prefix = "", string postfix = "")
- {
- this.joiner = joiner;
- this.prefix = prefix;
- this.postfix = postfix;
- }
-
- public string ResolveClauses(DynamicParameters p)
- {
- foreach (var item in this)
- {
- p.AddDynamicParams(item.Parameters);
- }
- return prefix + string.Join(joiner, this.Select(c => c.Sql)) + postfix;
- }
- }
-
- public class Template
- {
- readonly string sql;
- readonly SqlBuilder builder;
- readonly object initParams;
- int dataSeq = -1; // Unresolved
-
- public Template(SqlBuilder builder, string sql, dynamic parameters)
- {
- this.initParams = parameters;
- this.sql = sql;
- this.builder = builder;
- }
-
- static System.Text.RegularExpressions.Regex regex =
- new System.Text.RegularExpressions.Regex(@"\/\*\*.+\*\*\/", System.Text.RegularExpressions.RegexOptions.Compiled | System.Text.RegularExpressions.RegexOptions.Multiline);
-
- void ResolveSql()
- {
- if (dataSeq != builder.seq)
- {
- DynamicParameters 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;
- }
- }
-
- string rawSql;
- object parameters;
-
- public string RawSql { get { ResolveSql(); return rawSql; } }
- public object Parameters { get { ResolveSql(); return parameters; } }
- }
-
-
- public SqlBuilder()
- {
- }
-
- public Template AddTemplate(string sql, dynamic parameters = null)
- {
- return new Template(this, sql, parameters);
- }
-
- void AddClause(string name, string sql, object parameters, string joiner, string prefix = "", string postfix = "")
- {
- Clauses clauses;
- if (!data.TryGetValue(name, out clauses))
- {
- clauses = new Clauses(joiner, prefix, postfix);
- data[name] = clauses;
- }
- clauses.Add(new Clause { Sql = sql, Parameters = parameters });
- seq++;
- }
-
-
- public SqlBuilder LeftJoin(string sql, dynamic parameters = null)
- {
- AddClause("leftjoin", sql, parameters, joiner: "\nLEFT JOIN ", prefix: "\nLEFT JOIN ", postfix: "\n");
- return this;
- }
-
- public SqlBuilder Where(string sql, dynamic parameters = null)
- {
- AddClause("where", sql, parameters, " AND ", prefix: "WHERE ", postfix: "\n");
- return this;
- }
-
- public SqlBuilder OrderBy(string sql, dynamic parameters = null)
- {
- AddClause("orderby", sql, parameters, " , ", prefix: "ORDER BY ", postfix: "\n");
- return this;
- }
-
- public SqlBuilder Select(string sql, dynamic parameters = null)
- {
- AddClause("select", sql, parameters, " , ", prefix: "", postfix: "\n");
- return this;
- }
-
- public SqlBuilder AddParameters(dynamic parameters)
- {
- AddClause("--parameters", "", parameters, "");
- return this;
- }
-
- public SqlBuilder Join(string sql, dynamic parameters = null)
- {
- AddClause("join", sql, parameters, joiner: "\nJOIN ", prefix: "\nJOIN ", postfix: "\n");
- return this;
- }
-
- public SqlBuilder GroupBy(string sql, dynamic parameters = null)
- {
- AddClause("groupby", sql, parameters, joiner: " , ", prefix: "\nGROUP BY ", postfix: "\n");
- return this;
- }
-
- public SqlBuilder Having(string sql, dynamic parameters = null)
- {
- AddClause("having", sql, parameters, joiner: "\nAND ", prefix: "HAVING ", postfix: "\n");
- return this;
- }
- }
}
View
61 Dapper.Rainbow/Dapper.Rainbow.csproj
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{21BC6EA8-3D10-4CC9-A1B3-9FAD59F7D1BB}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Dapper.Rainbow</RootNamespace>
+ <AssemblyName>Dapper.Rainbow</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Database.cs" />
+ <Compile Include="Snapshotter.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Dapper\Dapper.csproj">
+ <Project>{DAF737E1-05B5-4189-A5AA-DAC6233B64D7}</Project>
+ <Name>Dapper</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
View
300 Dapper.Rainbow/Database.cs
@@ -0,0 +1,300 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+using System.Data;
+using Dapper;
+using System.Collections.Concurrent;
+using System.Reflection;
+using System.Text;
+using System.Data.Common;
+using System.Diagnostics;
+using System.Reflection.Emit;
+
+namespace Dapper
+{
+ /// <summary>
+ /// A container for a database, assumes all the tables have an Id column named Id
+ /// </summary>
+ /// <typeparam name="TDatabase"></typeparam>
+ public abstract class Database<TDatabase> : IDisposable where TDatabase : Database<TDatabase>, new()
+ {
+ public class Table<T>
+ {
+ Database<TDatabase> database;
+ string tableName;
+ string likelyTableName;
+
+ public Table(Database<TDatabase> database, string likelyTableName)
+ {
+ this.database = database;
+ this.likelyTableName = likelyTableName;
+ }
+
+ public string TableName
+ {
+ get
+ {
+ tableName = tableName ?? database.DetermineTableName<T>(likelyTableName);
+ return tableName;
+ }
+ }
+
+ /// <summary>
+ /// Insert a row into the db
+ /// </summary>
+ /// <param name="data">Either DynamicParameters or an anonymous type or concrete type</param>
+ /// <returns></returns>
+ public int? Insert(dynamic data)
+ {
+ var o = (object)data;
+ List<string> paramNames = GetParamNames(o);
+
+ string cols = string.Join(",", paramNames);
+ string cols_params = string.Join(",", paramNames.Select(p => "@" + p));
+ var sql = "set nocount on insert " + TableName + " (" + cols + ") values (" + cols_params + ") select cast(scope_identity() as int)";
+
+ return database.Query<int?>(sql, o).Single();
+ }
+
+ /// <summary>
+ /// Update a record in the DB
+ /// </summary>
+ /// <param name="id"></param>
+ /// <param name="data"></param>
+ /// <returns></returns>
+ public int Update(int id, dynamic data)
+ {
+ List<string> paramNames = GetParamNames(data);
+
+ var builder = new StringBuilder();
+ builder.Append("update [").Append(TableName).Append("] set ");
+ builder.AppendLine(string.Join(",", paramNames.Where(n => n != "Id").Select(p => p + "= @" + p)));
+ builder.Append("where Id = @Id");
+
+ DynamicParameters parameters = new DynamicParameters(data);
+ parameters.Add("Id", id);
+
+ return database.Execute(builder.ToString(), parameters);
+ }
+
+ /// <summary>
+ /// Delete a record for the DB
+ /// </summary>
+ /// <param name="id"></param>
+ /// <returns></returns>
+ public bool Delete(int id)
+ {
+ return database.Execute("delete " + TableName + " where Id = @id", new { id }) > 0;
+ }
+
+ /// <summary>
+ /// Grab a record with a particular Id from the DB
+ /// </summary>
+ /// <param name="id"></param>
+ /// <returns></returns>
+ public T Get(int id)
+ {
+ return database.Query<T>("select * from " + TableName + " where id = @id", new { id }).FirstOrDefault();
+ }
+
+ public T First()
+ {
+ return database.Query<T>("select top 1 * from " + TableName).FirstOrDefault();
+ }
+
+ public IEnumerable<T> All()
+ {
+ return database.Query<T>("select * from " + TableName);
+ }
+
+ static ConcurrentDictionary<Type, List<string>> paramNameCache = new ConcurrentDictionary<Type, List<string>>();
+ private static List<string> GetParamNames(object o)
+ {
+ if (o is DynamicParameters)
+ {
+ return (o as DynamicParameters).ParameterNames.ToList();
+ }
+
+ List<string> paramNames;
+ if (!paramNameCache.TryGetValue(o.GetType(), out paramNames))
+ {
+ paramNames = new List<string>();
+ foreach (var prop in o.GetType().GetProperties(BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public))
+ {
+ paramNames.Add(prop.Name);
+ }
+ paramNameCache[o.GetType()] = paramNames;
+ }
+ return paramNames;
+ }
+ }
+
+ DbConnection connection;
+ int commandTimeout;
+ DbTransaction transaction;
+
+
+ public static TDatabase Create(DbConnection connection, int commandTimeout)
+ {
+ TDatabase db = new TDatabase();
+ db.InitDatabase(connection, commandTimeout);
+ return db;
+ }
+
+ private static Action<Database<TDatabase>> tableConstructor;
+
+ private void InitDatabase(DbConnection connection, int commandTimeout)
+ {
+ this.connection = connection;
+ this.commandTimeout = commandTimeout;
+ if (tableConstructor == null)
+ {
+ tableConstructor = CreateTableConstructor();
+ }
+
+ tableConstructor(this);
+ }
+
+ public void BeginTransaction(IsolationLevel isolation = IsolationLevel.ReadCommitted)
+ {
+ transaction = connection.BeginTransaction(isolation);
+ }
+
+ public void CommitTransaction()
+ {
+ transaction.Commit();
+ transaction = null;
+ }
+
+ public void RollbackTransaction()
+ {
+ transaction.Rollback();
+ transaction = null;
+ }
+
+ public Action<Database<TDatabase>> CreateTableConstructor()
+ {
+ var dm = new DynamicMethod("ConstructInstances", null, new Type[] { typeof(Database<TDatabase>) }, true);
+ var il = dm.GetILGenerator();
+
+ var setters = GetType().GetProperties()
+ .Where(p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(Table<>))
+ .Select(p => Tuple.Create(
+ p.GetSetMethod(true),
+ p.PropertyType.GetConstructor(new Type[] { typeof(Database<TDatabase>), typeof(string) }),
+ p.Name,
+ p.DeclaringType
+ ));
+
+ foreach (var setter in setters)
+ {
+ il.Emit(OpCodes.Ldarg_0);
+ // [db]
+
+ il.Emit(OpCodes.Ldstr, setter.Item3);
+ // [db, likelyname]
+
+ il.Emit(OpCodes.Newobj, setter.Item2);
+ // [table]
+
+ var table = il.DeclareLocal(setter.Item2.DeclaringType);
+ il.Emit(OpCodes.Stloc, table);
+ // []
+
+ il.Emit(OpCodes.Ldarg_0);
+ // [db]
+
+ il.Emit(OpCodes.Castclass, setter.Item4);
+ // [db cast to container]
+
+ il.Emit(OpCodes.Ldloc, table);
+ // [db cast to container, table]
+
+ il.Emit(OpCodes.Callvirt, setter.Item1);
+ // []
+ }
+
+ il.Emit(OpCodes.Ret);
+ return (Action<Database<TDatabase>>)dm.CreateDelegate(typeof(Action<Database<TDatabase>>));
+ }
+
+ static ConcurrentDictionary<Type, string> tableNameMap = new ConcurrentDictionary<Type, string>();
+ private string DetermineTableName<T>(string likelyTableName)
+ {
+ string name;
+
+ if (!tableNameMap.TryGetValue(typeof(T), out name))
+ {
+ name = likelyTableName;
+ if (!TableExists(name))
+ {
+ name = typeof(T).Name;
+ }
+
+ tableNameMap[typeof(T)] = name;
+ }
+ return name;
+ }
+
+ private bool TableExists(string name)
+ {
+ return connection.Query("select 1 from INFORMATION_SCHEMA.TABLES where TABLE_NAME = @name", new { name }, transaction: transaction).Count() == 1;
+ }
+
+ public int Execute(string sql, dynamic param = null)
+ {
+ return SqlMapper.Execute(connection, sql, param as object, transaction, commandTimeout: this.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);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ public IEnumerable<dynamic> Query(string sql, dynamic param = null, bool buffered = true)
+ {
+ return SqlMapper.Query(connection, 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)
+ {
+ return SqlMapper.QueryMultiple(connection, sql, param, transaction, commandTimeout, commandType);
+ }
+
+
+ public void Dispose()
+ {
+ if (connection.State != ConnectionState.Closed)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ connection.Close();
+ connection = null;
+ }
+ }
+ }
+}
View
36 Dapper.Rainbow/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Dapper.Rainbow")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Dapper.Rainbow")]
+[assembly: AssemblyCopyright("Copyright © 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("e763c106-eef4-4654-afcc-c28fded057e5")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
View
204 Dapper.Rainbow/Snapshotter.cs
@@ -0,0 +1,204 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace Dapper
+{
+ public static class Snapshotter
+ {
+ public static Snapshot<T> Start<T>(T obj)
+ {
+ return new Snapshot<T>(obj);
+ }
+
+ public class Snapshot<T>
+ {
+ static Func<T, T> cloner;
+ static Func<T, T, List<Change>> differ;
+ T memberWiseClone;
+ T trackedObject;
+
+ public Snapshot(T original)
+ {
+ memberWiseClone = Clone(original);
+ trackedObject = original;
+ }
+
+ public class Change
+ {
+ public string Name { get; set; }
+ public object NewValue { get; set; }
+ }
+
+ public DynamicParameters Diff()
+ {
+ return Diff(memberWiseClone, trackedObject);
+ }
+
+
+ private static T Clone(T myObject)
+ {
+ cloner = cloner ?? GenerateCloner();
+ return cloner(myObject);
+ }
+
+ private static DynamicParameters Diff(T original, T current)
+ {
+ var dm = new DynamicParameters();
+ differ = differ ?? GenerateDiffer();
+ foreach (var pair in differ(original, current))
+ {
+ dm.Add(pair.Name, pair.NewValue);
+ }
+ return dm;
+ }
+
+
+ static List<PropertyInfo> RelevantProperties()
+ {
+ return typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public)
+ .Where(p =>
+ p.GetSetMethod() != null &&
+ p.GetGetMethod() != null &&
+ (p.PropertyType.IsValueType ||
+ p.PropertyType == typeof(string) ||
+ (p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)))
+ ).ToList();
+ }
+
+
+ private static bool AreEqual<U>(U first, U second)
+ {
+ if (first == null && second == null) return true;
+ if (first == null && second != null) return false;
+ return first.Equals(second);
+ }
+
+ private static Func<T, T, List<Change>> GenerateDiffer()
+ {
+
+ var dm = new DynamicMethod("DoDiff", typeof(List<Change>), new Type[] { typeof(T), typeof(T) }, true);
+
+ var il = dm.GetILGenerator();
+ // change list
+ il.DeclareLocal(typeof(List<Change>));
+ il.DeclareLocal(typeof(Change));
+ il.DeclareLocal(typeof(object)); // boxed change
+
+ il.Emit(OpCodes.Newobj, typeof(List<Change>).GetConstructor(Type.EmptyTypes));
+ // [list]
+ il.Emit(OpCodes.Stloc_0);
+
+ foreach (var prop in RelevantProperties())
+ {
+ // []
+ il.Emit(OpCodes.Ldarg_0);
+ // [original]
+ il.Emit(OpCodes.Callvirt, prop.GetGetMethod());
+ // [original prop val]
+ il.Emit(OpCodes.Ldarg_1);
+ // [original prop val, current]
+ il.Emit(OpCodes.Callvirt, prop.GetGetMethod());
+ // [original prop val, current prop val]
+
+ il.Emit(OpCodes.Dup);
+ // [original prop val, current prop val, current prop val]
+
+ if (prop.PropertyType != typeof(string))
+ {
+ il.Emit(OpCodes.Box, prop.PropertyType);
+ // [original prop val, current prop val, current prop val boxed]
+ }
+
+ il.Emit(OpCodes.Stloc_2);
+ // [original prop val, current prop val]
+
+ il.EmitCall(OpCodes.Call, typeof(Snapshot<T>).GetMethod("AreEqual", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(new Type[] { prop.PropertyType }), null);
+ // [result]
+
+ Label skip = il.DefineLabel();
+ il.Emit(OpCodes.Brtrue_S, skip);
+ // []
+
+ il.Emit(OpCodes.Newobj, typeof(Change).GetConstructor(Type.EmptyTypes));
+ // [change]
+ il.Emit(OpCodes.Dup);
+ // [change,change]
+
+ il.Emit(OpCodes.Stloc_1);
+ // [change]
+
+ il.Emit(OpCodes.Ldstr, prop.Name);
+ // [change, name]
+ il.Emit(OpCodes.Callvirt, typeof(Change).GetMethod("set_Name"));
+ // []
+
+ il.Emit(OpCodes.Ldloc_1);
+ // [change]
+
+ il.Emit(OpCodes.Ldloc_2);
+ // [change, boxed]
+
+ il.Emit(OpCodes.Callvirt, typeof(Change).GetMethod("set_NewValue"));
+ // []
+
+ il.Emit(OpCodes.Ldloc_0);
+ // [change list]
+ il.Emit(OpCodes.Ldloc_1);
+ // [change list, change]
+ il.Emit(OpCodes.Callvirt, typeof(List<Change>).GetMethod("Add"));
+ // []
+
+ il.MarkLabel(skip);
+ }
+
+ il.Emit(OpCodes.Ldloc_0);
+ // [change list]
+ il.Emit(OpCodes.Ret);
+
+ return (Func<T, T, List<Change>>)dm.CreateDelegate(typeof(Func<T, T, List<Change>>));
+ }
+
+
+ // adapted from http://stackoverflow.com/a/966466/17174
+ private static Func<T, T> GenerateCloner()
+ {
+ Delegate myExec = null;
+ var dm = new DynamicMethod("DoClone", typeof(T), new Type[] { typeof(T) }, true);
+ var ctor = typeof(T).GetConstructor(new Type[] { });
+
+ var il = dm.GetILGenerator();
+
+ il.DeclareLocal(typeof(T));
+
+ il.Emit(OpCodes.Newobj, ctor);
+ il.Emit(OpCodes.Stloc_0);
+
+ foreach (var prop in RelevantProperties())
+ {
+ il.Emit(OpCodes.Ldloc_0);
+ // [clone]
+ il.Emit(OpCodes.Ldarg_0);
+ // [clone, source]
+ il.Emit(OpCodes.Callvirt, prop.GetGetMethod());
+ // [clone, source val]
+ il.Emit(OpCodes.Callvirt, prop.GetSetMethod());
+ // []
+ }
+
+ // Load new constructed obj on eval stack -> 1 item on stack
+ il.Emit(OpCodes.Ldloc_0);
+ // Return constructed object. --> 0 items on stack
+ il.Emit(OpCodes.Ret);
+
+ myExec = dm.CreateDelegate(typeof(Func<T, T>));
+
+ return (Func<T, T>)myExec;
+ }
+ }
+ }
+}
+
View
60 Dapper.SqlBuilder/Dapper.SqlBuilder.csproj
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{BF782EF1-2B0F-42FA-9DD0-928454A94C6D}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Dapper.SqlBuilder</RootNamespace>
+ <AssemblyName>Dapper.SqlBuilder</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="SqlBuilder.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Dapper\Dapper.csproj">
+ <Project>{DAF737E1-05B5-4189-A5AA-DAC6233B64D7}</Project>
+ <Name>Dapper</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
View
36 Dapper.SqlBuilder/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Dapper.SqlBuilder")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Dapper.SqlBuilder")]
+[assembly: AssemblyCopyright("Copyright © 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("27491c26-c95d-44e5-b907-30559ef11265")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
View
158 Dapper.SqlBuilder/SqlBuilder.cs
@@ -0,0 +1,158 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Dapper
+{
+ public class SqlBuilder
+ {
+ Dictionary<string, Clauses> data = new Dictionary<string, Clauses>();
+ int seq;
+
+ class Clause
+ {
+ public string Sql { get; set; }
+ public object Parameters { get; set; }
+ }
+
+ class Clauses : List<Clause>
+ {
+ string joiner;
+ string prefix;
+ string postfix;
+
+ public Clauses(string joiner, string prefix = "", string postfix = "")
+ {
+ this.joiner = joiner;
+ this.prefix = prefix;
+ this.postfix = postfix;
+ }
+
+ public string ResolveClauses(DynamicParameters p)
+ {
+ foreach (var item in this)
+ {
+ p.AddDynamicParams(item.Parameters);
+ }
+ return prefix + string.Join(joiner, this.Select(c => c.Sql)) + postfix;
+ }
+ }
+
+ public class Template
+ {
+ readonly string sql;
+ readonly SqlBuilder builder;
+ readonly object initParams;
+ int dataSeq = -1; // Unresolved
+
+ public Template(SqlBuilder builder, string sql, dynamic parameters)
+ {
+ this.initParams = parameters;
+ this.sql = sql;
+ this.builder = builder;
+ }
+
+ static System.Text.RegularExpressions.Regex regex =
+ new System.Text.RegularExpressions.Regex(@"\/\*\*.+\*\*\/", System.Text.RegularExpressions.RegexOptions.Compiled | System.Text.RegularExpressions.RegexOptions.Multiline);
+
+ void ResolveSql()
+ {
+ if (dataSeq != builder.seq)
+ {
+ DynamicParameters 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;
+ }
+ }
+
+ string rawSql;
+ object parameters;
+
+ public string RawSql { get { ResolveSql(); return rawSql; } }
+ public object Parameters { get { ResolveSql(); return parameters; } }
+ }
+
+
+ public SqlBuilder()
+ {
+ }
+
+ public Template AddTemplate(string sql, dynamic parameters = null)
+ {
+ return new Template(this, sql, parameters);
+ }
+
+ void AddClause(string name, string sql, object parameters, string joiner, string prefix = "", string postfix = "")
+ {
+ Clauses clauses;
+ if (!data.TryGetValue(name, out clauses))
+ {
+ clauses = new Clauses(joiner, prefix, postfix);
+ data[name] = clauses;
+ }
+ clauses.Add(new Clause { Sql = sql, Parameters = parameters });
+ seq++;
+ }
+
+
+ public SqlBuilder LeftJoin(string sql, dynamic parameters = null)
+ {
+ AddClause("leftjoin", sql, parameters, joiner: "\nLEFT JOIN ", prefix: "\nLEFT JOIN ", postfix: "\n");
+ return this;
+ }
+
+ public SqlBuilder Where(string sql, dynamic parameters = null)
+ {
+ AddClause("where", sql, parameters, " AND ", prefix: "WHERE ", postfix: "\n");
+ return this;
+ }
+
+ public SqlBuilder OrderBy(string sql, dynamic parameters = null)
+ {
+ AddClause("orderby", sql, parameters, " , ", prefix: "ORDER BY ", postfix: "\n");
+ return this;
+ }
+
+ public SqlBuilder Select(string sql, dynamic parameters = null)
+ {
+ AddClause("select", sql, parameters, " , ", prefix: "", postfix: "\n");
+ return this;
+ }
+
+ public SqlBuilder AddParameters(dynamic parameters)
+ {
+ AddClause("--parameters", "", parameters, "");
+ return this;
+ }
+
+ public SqlBuilder Join(string sql, dynamic parameters = null)
+ {
+ AddClause("join", sql, parameters, joiner: "\nJOIN ", prefix: "\nJOIN ", postfix: "\n");
+ return this;
+ }
+
+ public SqlBuilder GroupBy(string sql, dynamic parameters = null)
+ {
+ AddClause("groupby", sql, parameters, joiner: " , ", prefix: "\nGROUP BY ", postfix: "\n");
+ return this;
+ }
+
+ public SqlBuilder Having(string sql, dynamic parameters = null)
+ {
+ AddClause("having", sql, parameters, joiner: "\nAND ", prefix: "HAVING ", postfix: "\n");
+ return this;
+ }
+ }
+}
View
24 Dapper.sln
@@ -13,6 +13,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapper.Contrib.Tests", "Dap
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DapperTests NET35", "DapperTests NET35\DapperTests NET35.csproj", "{3BAA9F79-BA0A-4092-B47B-20170DD47989}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapper.SqlBuilder", "Dapper.SqlBuilder\Dapper.SqlBuilder.csproj", "{BF782EF1-2B0F-42FA-9DD0-928454A94C6D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapper.Rainbow", "Dapper.Rainbow\Dapper.Rainbow.csproj", "{21BC6EA8-3D10-4CC9-A1B3-9FAD59F7D1BB}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -83,6 +87,26 @@ Global
{3BAA9F79-BA0A-4092-B47B-20170DD47989}.Release|Mixed Platforms.Build.0 = Release|x86
{3BAA9F79-BA0A-4092-B47B-20170DD47989}.Release|x86.ActiveCfg = Release|x86
{3BAA9F79-BA0A-4092-B47B-20170DD47989}.Release|x86.Build.0 = Release|x86
+ {BF782EF1-2B0F-42FA-9DD0-928454A94C6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BF782EF1-2B0F-42FA-9DD0-928454A94C6D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BF782EF1-2B0F-42FA-9DD0-928454A94C6D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {BF782EF1-2B0F-42FA-9DD0-928454A94C6D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {BF782EF1-2B0F-42FA-9DD0-928454A94C6D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {BF782EF1-2B0F-42FA-9DD0-928454A94C6D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BF782EF1-2B0F-42FA-9DD0-928454A94C6D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BF782EF1-2B0F-42FA-9DD0-928454A94C6D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {BF782EF1-2B0F-42FA-9DD0-928454A94C6D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {BF782EF1-2B0F-42FA-9DD0-928454A94C6D}.Release|x86.ActiveCfg = Release|Any CPU
+ {21BC6EA8-3D10-4CC9-A1B3-9FAD59F7D1BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {21BC6EA8-3D10-4CC9-A1B3-9FAD59F7D1BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {21BC6EA8-3D10-4CC9-A1B3-9FAD59F7D1BB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {21BC6EA8-3D10-4CC9-A1B3-9FAD59F7D1BB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {21BC6EA8-3D10-4CC9-A1B3-9FAD59F7D1BB}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {21BC6EA8-3D10-4CC9-A1B3-9FAD59F7D1BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {21BC6EA8-3D10-4CC9-A1B3-9FAD59F7D1BB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {21BC6EA8-3D10-4CC9-A1B3-9FAD59F7D1BB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {21BC6EA8-3D10-4CC9-A1B3-9FAD59F7D1BB}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {21BC6EA8-3D10-4CC9-A1B3-9FAD59F7D1BB}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
View
4 Dapper/Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.6.0.0")]
-[assembly: AssemblyFileVersion("1.6.0.0")]
+[assembly: AssemblyVersion("1.8.0.0")]
+[assembly: AssemblyFileVersion("1.8.0.0")]
View
12 Dapper/SqlMapper.cs
@@ -2101,6 +2101,18 @@ void SqlMapper.IDynamicParameters.AddParameters(IDbCommand command, SqlMapper.Id
}
/// <summary>
+ /// All the names of the param in the bag, use Get to yank them out
+ /// </summary>
+ public IEnumerable<string> ParameterNames
+ {
+ get
+ {
+ return parameters.Select(p => p.Key);
+ }
+ }
+
+
+ /// <summary>
/// Get the value of a parameter
/// </summary>
/// <typeparam name="T"></typeparam>
View
21 Dapper/dapper.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata schemaVersion="2">
<id>Dapper</id>
- <version>1.7</version>
+ <version>1.8</version>
<title>Dapper dot net</title>
<authors>Sam Saffron,Marc Gravell</authors>
<owners>Sam Saffron,Marc Gravell</owners>
@@ -11,15 +11,24 @@
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>A high performance Micro-ORM supporting Sql Server, MySQL, Sqlite, SqlCE, Firebird etc..</description>
<summary>A high performance Micro-ORM</summary>
- <tags>orm,sql,micro-orm</tags>
+ <tags>orm sql micro-orm</tags>
<frameworkAssemblies>
- <frameworkAssembly assemblyName="System.Core" targetFramework=".NETFramework4.0-Client, .NETFramework4.0" />
- <frameworkAssembly assemblyName="System" targetFramework=".NETFramework4.0-Client, .NETFramework4.0" />
- <frameworkAssembly assemblyName="System.Data" targetFramework=".NETFramework4.0-Client, .NETFramework4.0" />
+ <frameworkAssembly assemblyName="System.Core"/>
+ <frameworkAssembly assemblyName="System"/>
+ <frameworkAssembly assemblyName="System.Data"/>
<frameworkAssembly assemblyName="Microsoft.CSharp" targetFramework=".NETFramework4.0-Client, .NETFramework4.0" />
</frameworkAssemblies>
+ <releaseNotes>
+ * 1.8 - Started release notes
+ * Important: Dapper is now shipping as a DLL which will work on .net 3.5 or .net 4.0,
+ * This improves the debugging experience as you no longer break into dapper when SQL fails.
+ * Added: ParameterNames on DynamicParameters
+ </releaseNotes>
</metadata>
<files>
- <file src="SqlMapper.cs" target="content\Dapper\SqlMapper.cs" />
+ <file src="bin\Release\Dapper.dll" target="lib\net40" />
+ <file src="bin\Release\Dapper.pdb" target="lib\net40" />
+ <file src="..\Dapper NET35\bin\Release\Dapper.dll" target="lib\net35" />
+ <file src="..\Dapper NET35\bin\Release\Dapper.pdb" target="lib\net35" />
</files>
</package>

0 comments on commit c9160c1

Please sign in to comment.