diff --git a/NETCORE/Slickflow/Source/DLL/Dapper.dll b/NETCORE/Slickflow/Source/DLL/Dapper.dll
deleted file mode 100644
index fbdd721a..00000000
Binary files a/NETCORE/Slickflow/Source/DLL/Dapper.dll and /dev/null differ
diff --git a/NETCORE/Slickflow/Source/DLL/Slickflow.Graph.dll b/NETCORE/Slickflow/Source/DLL/Slickflow.Graph.dll
index 28cc5c88..88d1f43c 100644
Binary files a/NETCORE/Slickflow/Source/DLL/Slickflow.Graph.dll and b/NETCORE/Slickflow/Source/DLL/Slickflow.Graph.dll differ
diff --git a/NETCORE/Slickflow/Source/Dapper/Dapper.csproj b/NETCORE/Slickflow/Source/Dapper/Dapper.csproj
index 18aa9b0b..c4780c1e 100644
--- a/NETCORE/Slickflow/Source/Dapper/Dapper.csproj
+++ b/NETCORE/Slickflow/Source/Dapper/Dapper.csproj
@@ -1,80 +1,11 @@
-
-
-
+
+
- Debug
- AnyCPU
- {4DA6306B-B9F0-4E06-ACA0-2A1400DD9BD0}
- Library
- Properties
- Dapper
- Dapper
- v4.5
- 512
-
+ netcoreapp2.1
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
\ No newline at end of file
+
+
diff --git a/NETCORE/Slickflow/Source/Dapper/Properties/AssemblyInfo.cs b/NETCORE/Slickflow/Source/Dapper/Properties/AssemblyInfo.cs
deleted file mode 100644
index 0a258e94..00000000
--- a/NETCORE/Slickflow/Source/Dapper/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-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")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Dapper")]
-[assembly: AssemblyCopyright("Copyright © 2013")]
-[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("636ae73c-fc1a-4860-bf39-9dc183667cd5")]
-
-// 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")]
diff --git a/NETCORE/Slickflow/Source/Dapper/SqlMapperExtensions.cs b/NETCORE/Slickflow/Source/Dapper/SqlMapperExtensions.cs
deleted file mode 100644
index 3b197505..00000000
--- a/NETCORE/Slickflow/Source/Dapper/SqlMapperExtensions.cs
+++ /dev/null
@@ -1,534 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Data;
-using System.Diagnostics;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using System.Collections.Concurrent;
-using System.Reflection.Emit;
-using System.Threading;
-using System.Runtime.CompilerServices;
-
-namespace Dapper.Contrib.Extensions
-{
-
- public static class SqlMapperExtensions
- {
- public interface IProxy
- {
- bool IsDirty { get; set; }
- }
-
- private static readonly ConcurrentDictionary> KeyProperties = new ConcurrentDictionary>();
- private static readonly ConcurrentDictionary> TypeProperties = new ConcurrentDictionary>();
- private static readonly ConcurrentDictionary GetQueries = new ConcurrentDictionary();
- private static readonly ConcurrentDictionary TypeTableName = new ConcurrentDictionary();
-
- private static readonly Dictionary AdapterDictionary = new Dictionary() {
- {"sqlconnection", new SqlServerAdapter()},
- {"npgsqlconnection", new PostgresAdapter()}
- };
-
- private static IEnumerable KeyPropertiesCache(Type type)
- {
-
- IEnumerable pi;
- if (KeyProperties.TryGetValue(type.TypeHandle,out pi))
- {
- return pi;
- }
-
- var allProperties = TypePropertiesCache(type);
- var keyProperties = allProperties.Where(p => p.GetCustomAttributes(true).Any(a => a is KeyAttribute)).ToList();
-
- if (keyProperties.Count == 0)
- {
- var idProp = allProperties.Where(p => p.Name.ToLower() == "id").FirstOrDefault();
- if (idProp != null)
- {
- keyProperties.Add(idProp);
- }
- }
-
- KeyProperties[type.TypeHandle] = keyProperties;
- return keyProperties;
- }
- private static IEnumerable TypePropertiesCache(Type type)
- {
- IEnumerable pis;
- if (TypeProperties.TryGetValue(type.TypeHandle, out pis))
- {
- return pis;
- }
-
- var properties = type.GetProperties().Where(IsWriteable).ToArray();
- TypeProperties[type.TypeHandle] = properties;
- return properties;
- }
-
- public static bool IsWriteable(PropertyInfo pi)
- {
- object[] attributes = pi.GetCustomAttributes(typeof (WriteAttribute), false);
- if (attributes.Length == 1)
- {
- WriteAttribute write = (WriteAttribute) attributes[0];
- return write.Write;
- }
- return true;
- }
-
- ///
- /// Returns a single entity by a single id from table "Ts". T must be of interface type.
- /// Id must be marked with [Key] attribute.
- /// Created entity is tracked/intercepted for changes and used by the Update() extension.
- ///
- /// Interface type to create and populate
- /// Open SqlConnection
- /// Id of the entity to get, must be marked with [Key] attribute
- /// Entity of T
- public static T Get(this IDbConnection connection, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
- {
- var type = typeof(T);
- string sql;
- if (!GetQueries.TryGetValue(type.TypeHandle, out sql))
- {
- var keys = KeyPropertiesCache(type);
- if (keys.Count() > 1)
- throw new DataException("Get only supports an entity with a single [Key] property");
- if (keys.Count() == 0)
- throw new DataException("Get only supports en entity with a [Key] property");
-
- var onlyKey = keys.First();
-
- var name = GetTableName(type);
-
- // TODO: pluralizer
- // TODO: query information schema and only select fields that are both in information schema and underlying class / interface
- sql = "select * from " + name + " where " + onlyKey.Name + " = @id";
- GetQueries[type.TypeHandle] = sql;
- }
-
- var dynParms = new DynamicParameters();
- dynParms.Add("@id", id);
-
- T obj = null;
-
- if (type.IsInterface)
- {
- var res = connection.Query(sql, dynParms).FirstOrDefault() as IDictionary;
-
- if (res == null)
- return (T)((object)null);
-
- obj = ProxyGenerator.GetInterfaceProxy();
-
- foreach (var property in TypePropertiesCache(type))
- {
- var val = res[property.Name];
- property.SetValue(obj, val, null);
- }
-
- ((IProxy)obj).IsDirty = false; //reset change tracking and return
- }
- else
- {
- obj = connection.Query(sql, dynParms, transaction: transaction, commandTimeout: commandTimeout).FirstOrDefault();
- }
- return obj;
- }
-
- private static string GetTableName(Type type)
- {
- string name;
- if (!TypeTableName.TryGetValue(type.TypeHandle, out name))
- {
- name = type.Name + "s";
- if (type.IsInterface && name.StartsWith("I"))
- name = name.Substring(1);
-
- //NOTE: This as dynamic trick should be able to handle both our own Table-attribute as well as the one in EntityFramework
- var tableattr = type.GetCustomAttributes(false).Where(attr => attr.GetType().Name == "TableAttribute").SingleOrDefault() as
- dynamic;
- if (tableattr != null)
- name = tableattr.Name;
- TypeTableName[type.TypeHandle] = name;
- }
- return name;
- }
-
- ///
- /// Inserts an entity into table "Ts" and returns identity id.
- ///
- /// Open SqlConnection
- /// Entity to insert
- /// Identity of inserted entity
- public static long Insert(this IDbConnection connection, T entityToInsert, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
- {
-
- var type = typeof(T);
-
- var name = GetTableName(type);
-
- var sbColumnList = new StringBuilder(null);
-
- var allProperties = TypePropertiesCache(type);
- var keyProperties = KeyPropertiesCache(type);
- var allPropertiesExceptKey = allProperties.Except(keyProperties);
-
- for (var i = 0; i < allPropertiesExceptKey.Count(); i++)
- {
- var property = allPropertiesExceptKey.ElementAt(i);
- sbColumnList.AppendFormat("[{0}]", property.Name);
- if (i < allPropertiesExceptKey.Count() - 1)
- sbColumnList.Append(", ");
- }
-
- var sbParameterList = new StringBuilder(null);
- for (var i = 0; i < allPropertiesExceptKey.Count(); i++)
- {
- var property = allPropertiesExceptKey.ElementAt(i);
- sbParameterList.AppendFormat("@{0}", property.Name);
- if (i < allPropertiesExceptKey.Count() - 1)
- sbParameterList.Append(", ");
- }
- ISqlAdapter adapter = GetFormatter(connection);
- int id = adapter.Insert(connection, transaction, commandTimeout, name, sbColumnList.ToString(), sbParameterList.ToString(), keyProperties, entityToInsert);
- return id;
- }
-
- ///
- /// Updates entity in table "Ts", checks if the entity is modified if the entity is tracked by the Get() extension.
- ///
- /// Type to be updated
- /// Open SqlConnection
- /// Entity to be updated
- /// true if updated, false if not found or not modified (tracked entities)
- public static bool Update(this IDbConnection connection, T entityToUpdate, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
- {
- var proxy = entityToUpdate as IProxy;
- if (proxy != null)
- {
- if (!proxy.IsDirty) return false;
- }
-
- var type = typeof(T);
-
- var keyProperties = KeyPropertiesCache(type);
- if (!keyProperties.Any())
- throw new ArgumentException("Entity must have at least one [Key] property");
-
- var name = GetTableName(type);
-
- var sb = new StringBuilder();
- sb.AppendFormat("update {0} set ", name);
-
- var allProperties = TypePropertiesCache(type);
- var nonIdProps = allProperties.Where(a => !keyProperties.Contains(a));
-
- for (var i = 0; i < nonIdProps.Count(); i++)
- {
- var property = nonIdProps.ElementAt(i);
- sb.AppendFormat("{0} = @{1}", property.Name, property.Name);
- if (i < nonIdProps.Count() - 1)
- sb.AppendFormat(", ");
- }
- sb.Append(" where ");
- for (var i = 0; i < keyProperties.Count(); i++)
- {
- var property = keyProperties.ElementAt(i);
- sb.AppendFormat("{0} = @{1}", property.Name, property.Name);
- if (i < keyProperties.Count() - 1)
- sb.AppendFormat(" and ");
- }
- var updated = connection.Execute(sb.ToString(), entityToUpdate, commandTimeout: commandTimeout, transaction: transaction);
- return updated > 0;
- }
-
- ///
- /// Delete entity in table "Ts".
- ///
- /// Type of entity
- /// Open SqlConnection
- /// Entity to delete
- /// true if deleted, false if not found
- public static bool Delete(this IDbConnection connection, T entityToDelete, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
- {
- if (entityToDelete == null)
- throw new ArgumentException("Cannot Delete null Object", "entityToDelete");
-
- var type = typeof(T);
-
- var keyProperties = KeyPropertiesCache(type);
- if (keyProperties.Count() == 0)
- throw new ArgumentException("Entity must have at least one [Key] property");
-
- var name = GetTableName(type);
-
- var sb = new StringBuilder();
- sb.AppendFormat("delete from {0} where ", name);
-
- for (var i = 0; i < keyProperties.Count(); i++)
- {
- var property = keyProperties.ElementAt(i);
- sb.AppendFormat("{0} = @{1}", property.Name, property.Name);
- if (i < keyProperties.Count() - 1)
- sb.AppendFormat(" and ");
- }
- var deleted = connection.Execute(sb.ToString(), entityToDelete, transaction: transaction, commandTimeout: commandTimeout);
- return deleted > 0;
- }
-
- public static ISqlAdapter GetFormatter(IDbConnection connection)
- {
- string name = connection.GetType().Name.ToLower();
- if (!AdapterDictionary.ContainsKey(name))
- return new SqlServerAdapter();
- return AdapterDictionary[name];
- }
-
- class ProxyGenerator
- {
- private static readonly Dictionary TypeCache = new Dictionary();
-
- private static AssemblyBuilder GetAsmBuilder(string name)
- {
- var assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(new AssemblyName { Name = name },
- AssemblyBuilderAccess.Run); //NOTE: to save, use RunAndSave
-
- return assemblyBuilder;
- }
-
- public static T GetClassProxy()
- {
- // A class proxy could be implemented if all properties are virtual
- // otherwise there is a pretty dangerous case where internal actions will not update dirty tracking
- throw new NotImplementedException();
- }
-
-
- public static T GetInterfaceProxy()
- {
- Type typeOfT = typeof(T);
-
- object k;
- if (TypeCache.TryGetValue(typeOfT, out k))
- {
- return (T)k;
- }
- var assemblyBuilder = GetAsmBuilder(typeOfT.Name);
-
- var moduleBuilder = assemblyBuilder.DefineDynamicModule("SqlMapperExtensions." + typeOfT.Name); //NOTE: to save, add "asdasd.dll" parameter
-
- var interfaceType = typeof(Dapper.Contrib.Extensions.SqlMapperExtensions.IProxy);
- var typeBuilder = moduleBuilder.DefineType(typeOfT.Name + "_" + Guid.NewGuid(),
- TypeAttributes.Public | TypeAttributes.Class);
- typeBuilder.AddInterfaceImplementation(typeOfT);
- typeBuilder.AddInterfaceImplementation(interfaceType);
-
- //create our _isDirty field, which implements IProxy
- var setIsDirtyMethod = CreateIsDirtyProperty(typeBuilder);
-
- // Generate a field for each property, which implements the T
- foreach (var property in typeof(T).GetProperties())
- {
- var isId = property.GetCustomAttributes(true).Any(a => a is KeyAttribute);
- CreateProperty(typeBuilder, property.Name, property.PropertyType, setIsDirtyMethod, isId);
- }
-
- var generatedType = typeBuilder.CreateType();
-
- //assemblyBuilder.Save(name + ".dll"); //NOTE: to save, uncomment
-
- var generatedObject = Activator.CreateInstance(generatedType);
-
- TypeCache.Add(typeOfT, generatedObject);
- return (T)generatedObject;
- }
-
-
- private static MethodInfo CreateIsDirtyProperty(TypeBuilder typeBuilder)
- {
- var propType = typeof(bool);
- var field = typeBuilder.DefineField("_" + "IsDirty", propType, FieldAttributes.Private);
- var property = typeBuilder.DefineProperty("IsDirty",
- System.Reflection.PropertyAttributes.None,
- propType,
- new Type[] { propType });
-
- 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",
- getSetAttr,
- propType,
- Type.EmptyTypes);
- var currGetIL = currGetPropMthdBldr.GetILGenerator();
- currGetIL.Emit(OpCodes.Ldarg_0);
- currGetIL.Emit(OpCodes.Ldfld, field);
- currGetIL.Emit(OpCodes.Ret);
- var currSetPropMthdBldr = typeBuilder.DefineMethod("set_" + "IsDirty",
- getSetAttr,
- null,
- new Type[] { propType });
- var currSetIL = currSetPropMthdBldr.GetILGenerator();
- currSetIL.Emit(OpCodes.Ldarg_0);
- currSetIL.Emit(OpCodes.Ldarg_1);
- currSetIL.Emit(OpCodes.Stfld, field);
- currSetIL.Emit(OpCodes.Ret);
-
- property.SetGetMethod(currGetPropMthdBldr);
- property.SetSetMethod(currSetPropMthdBldr);
- var getMethod = typeof(Dapper.Contrib.Extensions.SqlMapperExtensions.IProxy).GetMethod("get_" + "IsDirty");
- var setMethod = typeof(Dapper.Contrib.Extensions.SqlMapperExtensions.IProxy).GetMethod("set_" + "IsDirty");
- typeBuilder.DefineMethodOverride(currGetPropMthdBldr, getMethod);
- typeBuilder.DefineMethodOverride(currSetPropMthdBldr, setMethod);
-
- return currSetPropMthdBldr;
- }
-
- private static void CreateProperty(TypeBuilder typeBuilder, string propertyName, Type propType, MethodInfo setIsDirtyMethod, bool isIdentity)
- {
- //Define the field and the property
- var field = typeBuilder.DefineField("_" + propertyName, propType, FieldAttributes.Private);
- var property = typeBuilder.DefineProperty(propertyName,
- System.Reflection.PropertyAttributes.None,
- propType,
- new Type[] { propType });
-
- const MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.Virtual |
- MethodAttributes.HideBySig;
-
- // Define the "get" and "set" accessor methods
- var currGetPropMthdBldr = typeBuilder.DefineMethod("get_" + propertyName,
- getSetAttr,
- propType,
- Type.EmptyTypes);
-
- var currGetIL = currGetPropMthdBldr.GetILGenerator();
- currGetIL.Emit(OpCodes.Ldarg_0);
- currGetIL.Emit(OpCodes.Ldfld, field);
- currGetIL.Emit(OpCodes.Ret);
-
- var currSetPropMthdBldr = typeBuilder.DefineMethod("set_" + propertyName,
- getSetAttr,
- null,
- new Type[] { propType });
-
- //store value in private field and set the isdirty flag
- var currSetIL = currSetPropMthdBldr.GetILGenerator();
- currSetIL.Emit(OpCodes.Ldarg_0);
- currSetIL.Emit(OpCodes.Ldarg_1);
- currSetIL.Emit(OpCodes.Stfld, field);
- currSetIL.Emit(OpCodes.Ldarg_0);
- currSetIL.Emit(OpCodes.Ldc_I4_1);
- currSetIL.Emit(OpCodes.Call, setIsDirtyMethod);
- currSetIL.Emit(OpCodes.Ret);
-
- //TODO: Should copy all attributes defined by the interface?
- if (isIdentity)
- {
- var keyAttribute = typeof(KeyAttribute);
- var myConstructorInfo = keyAttribute.GetConstructor(new Type[] { });
- var attributeBuilder = new CustomAttributeBuilder(myConstructorInfo, new object[] { });
- property.SetCustomAttribute(attributeBuilder);
- }
-
- property.SetGetMethod(currGetPropMthdBldr);
- property.SetSetMethod(currSetPropMthdBldr);
- var getMethod = typeof(T).GetMethod("get_" + propertyName);
- var setMethod = typeof(T).GetMethod("set_" + propertyName);
- typeBuilder.DefineMethodOverride(currGetPropMthdBldr, getMethod);
- typeBuilder.DefineMethodOverride(currSetPropMthdBldr, setMethod);
- }
-
- }
- }
-
- [AttributeUsage(AttributeTargets.Class)]
- public class TableAttribute : Attribute
- {
- public TableAttribute(string tableName)
- {
- Name = tableName;
- }
- public string Name { get; private set; }
- }
-
- // do not want to depend on data annotations that is not in client profile
- [AttributeUsage(AttributeTargets.Property)]
- public class KeyAttribute : Attribute
- {
- }
-
- [AttributeUsage(AttributeTargets.Property)]
- public class WriteAttribute : Attribute
- {
- public WriteAttribute(bool write)
- {
- Write = write;
- }
- public bool Write { get; private set; }
- }
-}
-
-public interface ISqlAdapter
-{
- int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, String tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert);
-}
-
-public class SqlServerAdapter : ISqlAdapter
-{
- public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, String tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert)
- {
- string cmd = String.Format("insert into {0} ({1}) values ({2})", tableName, columnList, parameterList);
-
- connection.Execute(cmd, entityToInsert, transaction: transaction, commandTimeout: commandTimeout);
-
- //NOTE: would prefer to use IDENT_CURRENT('tablename') or IDENT_SCOPE but these are not available on SQLCE
- var r = connection.Query("select @@IDENTITY id", transaction: transaction, commandTimeout: commandTimeout);
- int id = (int)r.First().id;
- if (keyProperties.Any())
- keyProperties.First().SetValue(entityToInsert, id, null);
- return id;
- }
-}
-
-public class PostgresAdapter : ISqlAdapter
-{
- public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, String tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert)
- {
- StringBuilder sb = new StringBuilder();
- sb.AppendFormat("insert into {0} ({1}) values ({2})", tableName, columnList, parameterList);
-
- // If no primary key then safe to assume a join table with not too much data to return
- if (!keyProperties.Any())
- sb.Append(" RETURNING *");
- else
- {
- sb.Append(" RETURNING ");
- bool first = true;
- foreach (var property in keyProperties)
- {
- if (!first)
- sb.Append(", ");
- first = false;
- sb.Append(property.Name);
- }
- }
-
- var results = connection.Query(sb.ToString(), entityToInsert, transaction: transaction, commandTimeout: commandTimeout);
-
- // Return the key by assinging the corresponding property in the object - by product is that it supports compound primary keys
- int id = 0;
- foreach (var p in keyProperties)
- {
- var value = ((IDictionary)results.First())[p.Name.ToLower()];
- p.SetValue(entityToInsert, value, null);
- if (id == 0)
- id = Convert.ToInt32(value);
- }
- return id;
- }
-}
\ No newline at end of file
diff --git a/NETCORE/Slickflow/Source/Dommel/Dommel.csproj b/NETCORE/Slickflow/Source/Dommel/Dommel.csproj
deleted file mode 100644
index 0ae14966..00000000
--- a/NETCORE/Slickflow/Source/Dommel/Dommel.csproj
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
- Simple CRUD operations for Dapper.
- Copyright © Henk Mollema 2017
- Dommel
- 1.9.0
- Henk Mollema
- net45;net451;netstandard1.3
- true
- dommel;crud;dapper;database;orm
- https://github.com/henkmollema/Dommel
- https://github.com/henkmollema/Dommel/blob/master/LICENSE
- git
- https://github.com/henkmollema/Dommel
-
-
-
-
-
-
-
-
- 4.4.0
-
-
-
\ No newline at end of file
diff --git a/NETCORE/Slickflow/Source/Dommel/DommelMapper.cs b/NETCORE/Slickflow/Source/Dommel/DommelMapper.cs
deleted file mode 100644
index e350131d..00000000
--- a/NETCORE/Slickflow/Source/Dommel/DommelMapper.cs
+++ /dev/null
@@ -1,2143 +0,0 @@
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
-using System.Data;
-using System.Linq;
-using System.Linq.Expressions;
-using System.Reflection;
-using System.Text;
-using System.Threading.Tasks;
-using Dapper;
-
-namespace Dommel
-{
- ///
- /// Simple CRUD operations for Dapper.
- ///
- public static class DommelMapper
- {
- private static readonly Dictionary _sqlBuilders = new Dictionary
- {
- { "sqlconnection", new SqlServerSqlBuilder() },
- { "sqlceconnection", new SqlServerCeSqlBuilder() },
- { "sqliteconnection", new SqliteSqlBuilder() },
- { "npgsqlconnection", new PostgresSqlBuilder() },
- { "mysqlconnection", new MySqlSqlBuilder() }
- };
-
- private static readonly ConcurrentDictionary _getQueryCache = new ConcurrentDictionary();
- private static readonly ConcurrentDictionary _getAllQueryCache = new ConcurrentDictionary();
- private static readonly ConcurrentDictionary _insertQueryCache = new ConcurrentDictionary();
- private static readonly ConcurrentDictionary _updateQueryCache = new ConcurrentDictionary();
- private static readonly ConcurrentDictionary _deleteQueryCache = new ConcurrentDictionary();
- private static readonly ConcurrentDictionary _deleteAllQueryCache = new ConcurrentDictionary();
-
- ///
- /// Retrieves the entity of type with the specified id.
- ///
- /// The type of the entity.
- /// The connection to the database. This can either be open or closed.
- /// The id of the entity in the database.
- /// The entity with the corresponding id.
- public static TEntity Get(this IDbConnection connection, object id) where TEntity : class
- {
- DynamicParameters parameters;
- var sql = BuildGetById(typeof(TEntity), id, out parameters);
- return connection.QueryFirstOrDefault(sql, parameters);
- }
-
- ///
- /// Retrieves the entity of type with the specified id.
- ///
- /// The type of the entity.
- /// The connection to the database. This can either be open or closed.
- /// The id of the entity in the database.
- /// The transaction to the connection.
- /// The entity with the corresponding id.
- public static TEntity Get(this IDbConnection connection, object id, IDbTransaction transaction) where TEntity : class
- {
- DynamicParameters parameters;
- var sql = BuildGetById(typeof(TEntity), id, out parameters);
- return connection.QueryFirstOrDefault(sql, parameters, transaction);
- }
-
- ///
- /// Retrieves the entity of type with the specified id.
- ///
- /// The type of the entity.
- /// The connection to the database. This can either be open or closed.
- /// The id of the entity in the database.
- /// The entity with the corresponding id.
- public static Task GetAsync(this IDbConnection connection, object id) where TEntity : class
- {
- DynamicParameters parameters;
- var sql = BuildGetById(typeof(TEntity), id, out parameters);
- return connection.QueryFirstOrDefaultAsync(sql, parameters);
- }
-
- private static string BuildGetById(Type type, object id, out DynamicParameters parameters)
- {
- string sql;
- if (!_getQueryCache.TryGetValue(type, out sql))
- {
- var tableName = Resolvers.Table(type);
- var keyProperty = Resolvers.KeyProperty(type);
- var keyColumnName = Resolvers.Column(keyProperty);
-
- sql = $"select * from {tableName} where {keyColumnName} = @Id";
- _getQueryCache.TryAdd(type, sql);
- }
-
- parameters = new DynamicParameters();
- parameters.Add("Id", id);
-
- return sql;
- }
-
- ///
- /// Retrieves all the entities of type .
- ///
- /// The type of the entity.
- /// The connection to the database. This can either be open or closed.
- ///
- /// A value indicating whether the result of the query should be executed directly,
- /// or when the query is materialized (using ToList() for example).
- ///
- /// A collection of entities of type .
- public static IEnumerable GetAll(this IDbConnection connection, bool buffered = true) where TEntity : class
- {
- var sql = BuildGetAllQuery(typeof(TEntity));
- return connection.Query(sql, buffered: buffered);
- }
-
- ///
- /// Retrieves all the entities of type .
- ///
- /// The type of the entity.
- /// The connection to the database. This can either be open or closed.
- /// A collection of entities of type .
- public static Task> GetAllAsync(this IDbConnection connection) where TEntity : class
- {
- var sql = BuildGetAllQuery(typeof(TEntity));
- return connection.QueryAsync(sql);
- }
-
- private static string BuildGetAllQuery(Type type)
- {
- string sql;
- if (!_getAllQueryCache.TryGetValue(type, out sql))
- {
- var tableName = Resolvers.Table(type);
- sql = $"select * from {tableName}";
- _getAllQueryCache.TryAdd(type, sql);
- }
-
- return sql;
- }
-
- ///
- /// Retrieves the entity of type with the specified id
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The id of the entity in the database.
- /// The mapping to perform on the entities in the result set.
- /// The entity with the corresponding id joined with the specified types.
- public static TReturn Get(this IDbConnection connection, object id, Func map) where TReturn : class
- {
- return MultiMap(connection, map, id).FirstOrDefault();
- }
-
- ///
- /// Retrieves the entity of type with the specified id
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The id of the entity in the database.
- /// The mapping to perform on the entities in the result set.
- /// The entity with the corresponding id joined with the specified types.
- public static async Task GetAsync(this IDbConnection connection, object id, Func map) where TReturn : class
- {
- return (await MultiMapAsync(connection, map, id)).FirstOrDefault();
- }
-
- ///
- /// Retrieves the entity of type with the specified id
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The third type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The id of the entity in the database.
- /// The mapping to perform on the entities in the result set.
- /// The entity with the corresponding id joined with the specified types.
- public static TReturn Get(this IDbConnection connection,
- object id,
- Func map) where TReturn : class
- {
- return MultiMap(connection, map, id).FirstOrDefault();
- }
-
- ///
- /// Retrieves the entity of type with the specified id
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The third type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The id of the entity in the database.
- /// The mapping to perform on the entities in the result set.
- /// The entity with the corresponding id joined with the specified types.
- public static async Task GetAsync(this IDbConnection connection,
- object id,
- Func map) where TReturn : class
- {
- return (await MultiMapAsync(connection, map, id)).FirstOrDefault();
- }
-
- ///
- /// Retrieves the entity of type with the specified id
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The third type parameter.
- /// The fourth type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The id of the entity in the database.
- /// The mapping to perform on the entities in the result set.
- /// The entity with the corresponding id joined with the specified types.
- public static TReturn Get(this IDbConnection connection,
- object id,
- Func map) where TReturn : class
- {
- return MultiMap(connection, map, id).FirstOrDefault();
- }
-
- ///
- /// Retrieves the entity of type with the specified id
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The third type parameter.
- /// The fourth type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The id of the entity in the database.
- /// The mapping to perform on the entities in the result set.
- /// The entity with the corresponding id joined with the specified types.
- public static async Task GetAsync(this IDbConnection connection,
- object id,
- Func map) where TReturn : class
- {
- return (await MultiMapAsync(connection, map, id)).FirstOrDefault();
- }
-
- ///
- /// Retrieves the entity of type with the specified id
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The third type parameter.
- /// The fourth type parameter.
- /// The fifth type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The id of the entity in the database.
- /// The mapping to perform on the entities in the result set.
- /// The entity with the corresponding id joined with the specified types.
- public static TReturn Get(this IDbConnection connection,
- object id,
- Func map) where TReturn : class
- {
- return MultiMap(connection, map, id).FirstOrDefault();
- }
-
- ///
- /// Retrieves the entity of type with the specified id
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The third type parameter.
- /// The fourth type parameter.
- /// The fifth type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The id of the entity in the database.
- /// The mapping to perform on the entities in the result set.
- /// The entity with the corresponding id joined with the specified types.
- public static async Task GetAsync(this IDbConnection connection,
- object id,
- Func map) where TReturn : class
- {
- return (await MultiMapAsync(connection, map, id)).FirstOrDefault();
- }
-
- ///
- /// Retrieves the entity of type with the specified id
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The third type parameter.
- /// The fourth type parameter.
- /// The fifth type parameter.
- /// The sixth type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The id of the entity in the database.
- /// The mapping to perform on the entities in the result set.
- /// The entity with the corresponding id joined with the specified types.
- public static TReturn Get(this IDbConnection connection,
- object id,
- Func map) where TReturn : class
- {
- return MultiMap(connection, map, id).FirstOrDefault();
- }
-
- ///
- /// Retrieves the entity of type with the specified id
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The third type parameter.
- /// The fourth type parameter.
- /// The fifth type parameter.
- /// The sixth type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The id of the entity in the database.
- /// The mapping to perform on the entities in the result set.
- /// The entity with the corresponding id joined with the specified types.
- public static async Task GetAsync(this IDbConnection connection,
- object id,
- Func map) where TReturn : class
- {
- return (await MultiMapAsync(connection, map, id)).FirstOrDefault();
- }
-
- ///
- /// Retrieves the entity of type with the specified id
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The third type parameter.
- /// The fourth type parameter.
- /// The fifth type parameter.
- /// The sixth type parameter.
- /// The seventh type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The id of the entity in the database.
- /// The mapping to perform on the entities in the result set.
- /// The entity with the corresponding id joined with the specified types.
- public static TReturn Get(this IDbConnection connection,
- object id,
- Func map) where TReturn : class
- {
- return MultiMap(connection, map, id).FirstOrDefault();
- }
-
- ///
- /// Retrieves the entity of type with the specified id
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The third type parameter.
- /// The fourth type parameter.
- /// The fifth type parameter.
- /// The sixth type parameter.
- /// The seventh type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The id of the entity in the database.
- /// The mapping to perform on the entities in the result set.
- /// The entity with the corresponding id joined with the specified types.
- public static async Task GetAsync(this IDbConnection connection,
- object id,
- Func map) where TReturn : class
- {
- return (await MultiMapAsync(connection, map, id)).FirstOrDefault();
- }
-
- ///
- /// Retrieves all the entities of type
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The mapping to perform on the entities in the result set.
- ///
- /// A value indicating whether the result of the query should be executed directly,
- /// or when the query is materialized (using ToList() for example).
- ///
- ///
- /// A collection of entities of type
- /// joined with the specified type types.
- ///
- public static IEnumerable GetAll(this IDbConnection connection, Func map, bool buffered = true)
- {
- return MultiMap(connection, map, buffered: buffered);
- }
-
- ///
- /// Retrieves all the entities of type
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The mapping to perform on the entities in the result set.
- ///
- /// A value indicating whether the result of the query should be executed directly,
- /// or when the query is materialized (using ToList() for example).
- ///
- ///
- /// A collection of entities of type
- /// joined with the specified type types.
- ///
- public static Task> GetAllAsync(this IDbConnection connection, Func map, bool buffered = true)
- {
- return MultiMapAsync(connection, map, buffered: buffered);
- }
-
- ///
- /// Retrieves all the entities of type
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The third type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The mapping to perform on the entities in the result set.
- ///
- /// A value indicating whether the result of the query should be executed directly,
- /// or when the query is materialized (using ToList() for example).
- ///
- ///
- /// A collection of entities of type
- /// joined with the specified type types.
- ///
- public static IEnumerable GetAll(this IDbConnection connection, Func map, bool buffered = true)
- {
- return MultiMap(connection, map, buffered: buffered);
- }
-
- ///
- /// Retrieves all the entities of type
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The third type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The mapping to perform on the entities in the result set.
- ///
- /// A value indicating whether the result of the query should be executed directly,
- /// or when the query is materialized (using ToList() for example).
- ///
- ///
- /// A collection of entities of type
- /// joined with the specified type types.
- ///
- public static Task> GetAllAsync(this IDbConnection connection, Func map, bool buffered = true)
- {
- return MultiMapAsync(connection, map, buffered: buffered);
- }
-
- ///
- /// Retrieves all the entities of type
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The third type parameter.
- /// The fourth type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The mapping to perform on the entities in the result set.
- ///
- /// A value indicating whether the result of the query should be executed directly,
- /// or when the query is materialized (using ToList() for example).
- ///
- ///
- /// A collection of entities of type
- /// joined with the specified type types.
- ///
- public static IEnumerable GetAll(this IDbConnection connection, Func map, bool buffered = true)
- {
- return MultiMap(connection, map, buffered: buffered);
- }
-
- ///
- /// Retrieves all the entities of type
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The third type parameter.
- /// The fourth type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The mapping to perform on the entities in the result set.
- ///
- /// A value indicating whether the result of the query should be executed directly,
- /// or when the query is materialized (using ToList() for example).
- ///
- ///
- /// A collection of entities of type
- /// joined with the specified type types.
- ///
- public static Task> GetAllAsync(this IDbConnection connection, Func map, bool buffered = true)
- {
- return MultiMapAsync(connection, map, buffered: buffered);
- }
-
- ///
- /// Retrieves all the entities of type
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The third type parameter.
- /// The fourth type parameter.
- /// The fifth type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The mapping to perform on the entities in the result set.
- ///
- /// A value indicating whether the result of the query should be executed directly,
- /// or when the query is materialized (using ToList() for example).
- ///
- ///
- /// A collection of entities of type
- /// joined with the specified type types.
- ///
- public static IEnumerable GetAll(this IDbConnection connection, Func map, bool buffered = true)
- {
- return MultiMap(connection, map, buffered: buffered);
- }
-
- ///
- /// Retrieves all the entities of type
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The third type parameter.
- /// The fourth type parameter.
- /// The fifth type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The mapping to perform on the entities in the result set.
- ///
- /// A value indicating whether the result of the query should be executed directly,
- /// or when the query is materialized (using ToList() for example).
- ///
- ///
- /// A collection of entities of type
- /// joined with the specified type types.
- ///
- public static Task> GetAllAsync(this IDbConnection connection, Func map, bool buffered = true)
- {
- return MultiMapAsync(connection, map, buffered: buffered);
- }
-
- ///
- /// Retrieves all the entities of type
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The third type parameter.
- /// The fourth type parameter.
- /// The fifth type parameter.
- /// The sixth type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The mapping to perform on the entities in the result set.
- ///
- /// A value indicating whether the result of the query should be executed directly,
- /// or when the query is materialized (using ToList() for example).
- ///
- ///
- /// A collection of entities of type
- /// joined with the specified type types.
- ///
- public static IEnumerable GetAll(this IDbConnection connection, Func map, bool buffered = true)
- {
- return MultiMap(connection, map, buffered: buffered);
- }
-
- ///
- /// Retrieves all the entities of type
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The third type parameter.
- /// The fourth type parameter.
- /// The fifth type parameter.
- /// The sixth type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The mapping to perform on the entities in the result set.
- ///
- /// A value indicating whether the result of the query should be executed directly,
- /// or when the query is materialized (using ToList() for example).
- ///
- ///
- /// A collection of entities of type
- /// joined with the specified type types.
- ///
- public static Task> GetAllAsync(this IDbConnection connection, Func map, bool buffered = true)
- {
- return MultiMapAsync(connection, map, buffered: buffered);
- }
-
- ///
- /// Retrieves all the entities of type
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The third type parameter.
- /// The fourth type parameter.
- /// The fifth type parameter.
- /// The sixth type parameter.
- /// The seventh type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The mapping to perform on the entities in the result set.
- ///
- /// A value indicating whether the result of the query should be executed directly,
- /// or when the query is materialized (using ToList() for example).
- ///
- ///
- /// A collection of entities of type
- /// joined with the specified type types.
- ///
- public static IEnumerable GetAll(this IDbConnection connection, Func map, bool buffered = true)
- {
- return MultiMap(connection, map, buffered: buffered);
- }
-
- ///
- /// Retrieves all the entities of type
- /// joined with the types specified as type parameters.
- ///
- /// The first type parameter. This is the source entity.
- /// The second type parameter.
- /// The third type parameter.
- /// The fourth type parameter.
- /// The fifth type parameter.
- /// The sixth type parameter.
- /// The seventh type parameter.
- /// The return type parameter.
- /// The connection to the database. This can either be open or closed.
- /// The mapping to perform on the entities in the result set.
- ///
- /// A value indicating whether the result of the query should be executed directly,
- /// or when the query is materialized (using ToList() for example).
- ///
- ///
- /// A collection of entities of type
- /// joined with the specified type types.
- ///
- public static Task> GetAllAsync(this IDbConnection connection, Func map, bool buffered = true)
- {
- return MultiMapAsync(connection, map, buffered: buffered);
- }
-
- private static IEnumerable MultiMap(IDbConnection connection, Delegate map, object id = null, bool buffered = true)
- {
- var resultType = typeof(TReturn);
- var
- includeTypes = new[]
- {
- typeof(T1),
- typeof(T2),
- typeof(T3),
- typeof(T4),
- typeof(T5),
- typeof(T6),
- typeof(T7)
- }
- .Where(t => t != typeof(DontMap))
- .ToArray();
-
- DynamicParameters parameters;
- var sql = BuildMultiMapQuery(resultType, includeTypes, id, out parameters);
-
- switch (includeTypes.Length)
- {
- case 2:
- return connection.Query(sql, (Func)map, parameters, buffered: buffered);
- case 3:
- return connection.Query(sql, (Func)map, parameters, buffered: buffered);
- case 4:
- return connection.Query(sql, (Func)map, parameters, buffered: buffered);
- case 5:
- return connection.Query(sql, (Func)map, parameters, buffered: buffered);
- case 6:
- return connection.Query(sql, (Func)map, parameters, buffered: buffered);
- case 7:
- return connection.Query(sql, (Func)map, parameters, buffered: buffered);
- }
-
- throw new InvalidOperationException($"Invalid amount of include types: {includeTypes.Length}.");
- }
-
- private static Task> MultiMapAsync(IDbConnection connection, Delegate map, object id = null, bool buffered = true)
- {
- var resultType = typeof(TReturn);
- var
- includeTypes = new[]
- {
- typeof(T1),
- typeof(T2),
- typeof(T3),
- typeof(T4),
- typeof(T5),
- typeof(T6),
- typeof(T7)
- }
- .Where(t => t != typeof(DontMap))
- .ToArray();
-
- DynamicParameters parameters;
- var sql = BuildMultiMapQuery(resultType, includeTypes, id, out parameters);
-
- switch (includeTypes.Length)
- {
- case 2:
- return connection.QueryAsync(sql, (Func)map, parameters, buffered: buffered);
- case 3:
- return connection.QueryAsync(sql, (Func)map, parameters, buffered: buffered);
- case 4:
- return connection.QueryAsync(sql, (Func)map, parameters, buffered: buffered);
- case 5:
- return connection.QueryAsync(sql, (Func)map, parameters, buffered: buffered);
- case 6:
- return connection.QueryAsync(sql, (Func)map, parameters, buffered: buffered);
- case 7:
- return connection.QueryAsync(sql, (Func)map, parameters, buffered: buffered);
- }
-
- throw new InvalidOperationException($"Invalid amount of include types: {includeTypes.Length}.");
- }
-
- private static string BuildMultiMapQuery(Type resultType, Type[] includeTypes, object id, out DynamicParameters parameters)
- {
- var resultTableName = Resolvers.Table(resultType);
- var resultTableKeyColumnName = Resolvers.Column(Resolvers.KeyProperty(resultType));
-
- var sql = $"select * from {resultTableName}";
-
- for (var i = 1; i < includeTypes.Length; i++)
- {
- // Determine the table to join with.
- var sourceType = includeTypes[i - 1];
- var sourceTableName = Resolvers.Table(sourceType);
-
- // Determine the table name of the joined table.
- var includeType = includeTypes[i];
- var foreignKeyTableName = Resolvers.Table(includeType);
-
- // Determine the foreign key and the relationship type.
- ForeignKeyRelation relation;
- var foreignKeyProperty = Resolvers.ForeignKeyProperty(sourceType, includeType, out relation);
- var foreignKeyPropertyName = Resolvers.Column(foreignKeyProperty);
-
- // If the foreign key property is nullable, use a left-join.
- var joinType = Nullable.GetUnderlyingType(foreignKeyProperty.PropertyType) != null
- ? "left"
- : "inner";
-
- switch (relation)
- {
- case ForeignKeyRelation.OneToOne:
- // Determine the primary key of the foreign key table.
- var foreignKeyTableKeyColumName = Resolvers.Column(Resolvers.KeyProperty(includeType));
-
- sql += string.Format(" {0} join {1} on {2}.{3} = {1}.{4}",
- joinType,
- foreignKeyTableName,
- sourceTableName,
- foreignKeyPropertyName,
- foreignKeyTableKeyColumName);
- break;
-
- case ForeignKeyRelation.OneToMany:
- // Determine the primary key of the source table.
- var sourceKeyColumnName = Resolvers.Column(Resolvers.KeyProperty(sourceType));
-
- sql += string.Format(" {0} join {1} on {2}.{3} = {1}.{4}",
- joinType,
- foreignKeyTableName,
- sourceTableName,
- sourceKeyColumnName,
- foreignKeyPropertyName);
- break;
-
- case ForeignKeyRelation.ManyToMany:
- throw new NotImplementedException("Many-to-many relationships are not supported yet.");
-
- default:
- throw new NotImplementedException($"Foreign key relation type '{relation}' is not implemented.");
- }
- }
-
- parameters = null;
- if (id != null)
- {
- sql += string.Format(" where {0}.{1} = @{1}", resultTableName, resultTableKeyColumnName);
-
- parameters = new DynamicParameters();
- parameters.Add("Id", id);
- }
-
- return sql;
- }
-
- private class DontMap
- {
- }
-
- ///
- /// Selects all the entities matching the specified predicate.
- ///
- /// The type of the entity.
- /// The connection to the database. This can either be open or closed.
- /// A predicate to filter the results.
- ///
- /// A value indicating whether the result of the query should be executed directly,
- /// or when the query is materialized (using ToList() for example).
- ///
- ///
- /// A collection of entities of type matching the specified
- /// .
- ///
- public static IEnumerable Select(this IDbConnection connection, Expression> predicate, bool buffered = true)
- {
- DynamicParameters parameters;
- var sql = BuildSelectSql(predicate, out parameters);
- return connection.Query(sql, parameters, buffered: buffered);
- }
-
- ///
- /// Selects all the entities matching the specified predicate.
- ///
- /// The type of the entity.
- /// The connection to the database. This can either be open or closed.
- /// A predicate to filter the results.
- ///
- /// A collection of entities of type matching the specified
- /// .
- ///
- public static Task> SelectAsync(this IDbConnection connection, Expression> predicate)
- {
- DynamicParameters parameters;
- var sql = BuildSelectSql(predicate, out parameters);
- return connection.QueryAsync(sql, parameters);
- }
-
- private static string BuildSelectSql(Expression> predicate, out DynamicParameters parameters)
- {
- var type = typeof(TEntity);
- string sql;
- if (!_getAllQueryCache.TryGetValue(type, out sql))
- {
- var tableName = Resolvers.Table(type);
- sql = $"select * from {tableName}";
- _getAllQueryCache.TryAdd(type, sql);
- }
-
- sql += new SqlExpression()
- .Where(predicate)
- .ToSql(out parameters);
- return sql;
- }
-
- ///
- /// Selects the first entity matching the specified predicate, or a default value if no entity matched.
- ///
- /// The type of the entity.
- /// The connection to the database. This can either be open or closed.
- /// A predicate to filter the results.
- ///
- /// A instance of type matching the specified
- /// .
- ///
- public static TEntity FirstOrDefault(this IDbConnection connection, Expression> predicate)
- {
- DynamicParameters parameters;
- var sql = BuildSelectSql(predicate, out parameters);
- return connection.QueryFirstOrDefault(sql, parameters);
- }
-
- ///
- /// Selects the first entity matching the specified predicate, or a default value if no entity matched.
- ///
- /// The type of the entity.
- /// The connection to the database. This can either be open or closed.
- /// A predicate to filter the results.
- ///
- /// A instance of type matching the specified
- /// .
- ///
- public static Task FirstOrDefaultAsync(this IDbConnection connection, Expression> predicate)
- {
- DynamicParameters parameters;
- var sql = BuildSelectSql(predicate, out parameters);
- return connection.QueryFirstOrDefaultAsync(sql, parameters);
- }
-
- ///
- /// Represents a typed SQL expression.
- ///
- /// The type of the entity.
- public class SqlExpression
- {
- private readonly StringBuilder _whereBuilder = new StringBuilder();
- private readonly DynamicParameters _parameters = new DynamicParameters();
- private int _parameterIndex;
-
- ///
- /// Builds a SQL expression for the specified filter expression.
- ///
- /// The filter expression on the entity.
- /// The current instance.
- public virtual SqlExpression Where(Expression> expression)
- {
- if (expression != null)
- {
- AppendToWhere("and", expression);
- }
- return this;
- }
-
- private void AppendToWhere(string conditionOperator, Expression expression)
- {
- var sqlExpression = VisitExpression(expression).ToString();
- AppendToWhere(conditionOperator, sqlExpression);
- }
-
- private void AppendToWhere(string conditionOperator, string sqlExpression)
- {
- if (_whereBuilder.Length == 0)
- {
- _whereBuilder.Append(" where ");
- }
- else
- {
- _whereBuilder.AppendFormat(" {0} ", conditionOperator);
- }
-
- _whereBuilder.Append(sqlExpression);
- }
-
- ///
- /// Visits the expression.
- ///
- /// The expression to visit.
- /// The result of the visit.
- protected virtual object VisitExpression(Expression expression)
- {
- switch (expression.NodeType)
- {
- case ExpressionType.Lambda:
- return VisitLambda(expression as LambdaExpression);
-
- case ExpressionType.LessThan:
- case ExpressionType.LessThanOrEqual:
- case ExpressionType.GreaterThan:
- case ExpressionType.GreaterThanOrEqual:
- case ExpressionType.Equal:
- case ExpressionType.NotEqual:
- case ExpressionType.And:
- case ExpressionType.AndAlso:
- case ExpressionType.Or:
- case ExpressionType.OrElse:
- return VisitBinary((BinaryExpression)expression);
-
- case ExpressionType.Convert:
- case ExpressionType.Not:
- return VisitUnary((UnaryExpression)expression);
-
- case ExpressionType.New:
- return VisitNew((NewExpression)expression);
-
- case ExpressionType.MemberAccess:
- return VisitMemberAccess((MemberExpression)expression);
-
- case ExpressionType.Constant:
- return VisitConstantExpression((ConstantExpression)expression);
- }
-
- return expression;
- }
-
- ///
- /// Processes a lambda expression.
- ///
- /// The lambda expression.
- /// The result of the processing.
- protected virtual object VisitLambda(LambdaExpression epxression)
- {
- if (epxression.Body.NodeType == ExpressionType.MemberAccess)
- {
- var member = epxression.Body as MemberExpression;
- if (member?.Expression != null)
- {
- return $"{VisitMemberAccess(member)} = '1'";
- }
- }
-
- return VisitExpression(epxression.Body);
- }
-
- ///
- /// Processes a binary expression.
- ///
- /// The binary expression.
- /// The result of the processing.
- protected virtual object VisitBinary(BinaryExpression expression)
- {
- object left, right;
- var operand = BindOperant(expression.NodeType);
- if (operand == "and" || operand == "or")
- {
- // Left side.
- var member = expression.Left as MemberExpression;
- if (member != null &&
- member.Expression != null &&
- member.Expression.NodeType == ExpressionType.Parameter)
- {
- left = $"{VisitMemberAccess(member)} = '1'";
- }
- else
- {
- left = VisitExpression(expression.Left);
- }
-
- // Right side.
- member = expression.Right as MemberExpression;
- if (member != null &&
- member.Expression != null &&
- member.Expression.NodeType == ExpressionType.Parameter)
- {
- right = $"{VisitMemberAccess(member)} = '1'";
- }
- else
- {
- right = VisitExpression(expression.Right);
- }
- }
- else
- {
- // It's a single expression.
- left = VisitExpression(expression.Left);
- right = VisitExpression(expression.Right);
-
- var paramName = "p" + _parameterIndex++;
- _parameters.Add(paramName, value: right);
- return $"{left} {operand} @{paramName}";
- }
-
- return $"{left} {operand} {right}";
- }
-
- ///
- /// Processes a unary expression.
- ///
- /// The unary expression.
- /// The result of the processing.
- protected virtual object VisitUnary(UnaryExpression expression)
- {
- switch (expression.NodeType)
- {
- case ExpressionType.Not:
- var o = VisitExpression(expression.Operand);
- if (!(o is string))
- {
- return !(bool)o;
- }
-
- var memberExpression = expression.Operand as MemberExpression;
- if (memberExpression != null &&
- Resolvers.Properties(memberExpression.Expression.Type).Any(p => p.Name == (string)o))
- {
- o = $"{o} = '1'";
- }
-
- return $"not ({o})";
- case ExpressionType.Convert:
- if (expression.Method != null)
- {
- return Expression.Lambda(expression).Compile().DynamicInvoke();
- }
- break;
- }
-
- return VisitExpression(expression.Operand);
- }
-
- ///
- /// Processes a new expression.
- ///
- /// The new expression.
- /// The result of the processing.
- protected virtual object VisitNew(NewExpression expression)
- {
- var member = Expression.Convert(expression, typeof(object));
- var lambda = Expression.Lambda>(member);
- var getter = lambda.Compile();
- return getter();
- }
-
- ///
- /// Processes a member access expression.
- ///
- /// The member access expression.
- /// The result of the processing.
- protected virtual object VisitMemberAccess(MemberExpression expression)
- {
- if (expression.Expression != null && expression.Expression.NodeType == ExpressionType.Parameter)
- {
- return MemberToColumn(expression);
- }
-
- var member = Expression.Convert(expression, typeof(object));
- var lambda = Expression.Lambda>(member);
- var getter = lambda.Compile();
- return getter();
- }
-
- ///
- /// Processes a constant expression.
- ///
- /// The constant expression.
- /// The result of the processing.
- protected virtual object VisitConstantExpression(ConstantExpression expression)
- {
- return expression.Value ?? "null";
- }
-
- ///
- /// Proccesses a member expression.
- ///
- /// The member expression.
- /// The result of the processing.
- protected virtual string MemberToColumn(MemberExpression expression)
- {
- return Resolvers.Column((PropertyInfo)expression.Member);
- }
-
- ///
- /// Returns the expression operand for the specified expression type.
- ///
- /// The expression type for node of an expression tree.
- /// The expression operand equivalent of the .
- protected virtual string BindOperant(ExpressionType expressionType)
- {
- switch (expressionType)
- {
- case ExpressionType.Equal:
- return "=";
- case ExpressionType.NotEqual:
- return "<>";
- case ExpressionType.GreaterThan:
- return ">";
- case ExpressionType.GreaterThanOrEqual:
- return ">=";
- case ExpressionType.LessThan:
- return "<";
- case ExpressionType.LessThanOrEqual:
- return "<=";
- case ExpressionType.AndAlso:
- return "and";
- case ExpressionType.OrElse:
- return "or";
- case ExpressionType.Add:
- return "+";
- case ExpressionType.Subtract:
- return "-";
- case ExpressionType.Multiply:
- return "*";
- case ExpressionType.Divide:
- return "/";
- case ExpressionType.Modulo:
- return "MOD";
- case ExpressionType.Coalesce:
- return "COALESCE";
- default:
- return expressionType.ToString();
- }
- }
-
- ///
- /// Returns the current SQL query.
- ///
- /// The current SQL query.
- public string ToSql()
- {
- return _whereBuilder.ToString();
- }
-
- ///
- /// Returns the current SQL query.
- ///
- /// When this method returns, contains the parameters for the query.
- /// The current SQL query.
- public string ToSql(out DynamicParameters parameters)
- {
- parameters = _parameters;
- return _whereBuilder.ToString();
- }
-
- ///
- /// Returns the current SQL query.
- ///
- /// The current SQL query.
- public override string ToString()
- {
- return _whereBuilder.ToString();
- }
- }
-
- ///
- /// Inserts the specified entity into the database and returns the id.
- ///
- /// The type of the entity.
- /// The connection to the database. This can either be open or closed.
- /// The entity to be inserted.
- /// Optional transaction for the command.
- /// The id of the inserted entity.
- public static object Insert(this IDbConnection connection, TEntity entity, IDbTransaction transaction = null) where TEntity : class
- {
- var sql = BuildInsertQuery(connection, typeof(TEntity));
- return connection.ExecuteScalar(sql, entity, transaction);
- }
-
- ///
- /// Inserts the specified entity into the database and returns the id.
- ///
- /// The type of the entity.
- /// The connection to the database. This can either be open or closed.
- /// The entity to be inserted.
- /// Optional transaction for the command.
- /// The id of the inserted entity.
- public static Task