diff --git a/Api/Ewide.Core/Ewide.Core.Arguments/Ewide.Core.Arguments.csproj b/Api/Ewide.Core/Ewide.Core.Arguments/Ewide.Core.DTO.csproj
similarity index 89%
rename from Api/Ewide.Core/Ewide.Core.Arguments/Ewide.Core.Arguments.csproj
rename to Api/Ewide.Core/Ewide.Core.Arguments/Ewide.Core.DTO.csproj
index 0dafae7..1f26cf9 100644
--- a/Api/Ewide.Core/Ewide.Core.Arguments/Ewide.Core.Arguments.csproj
+++ b/Api/Ewide.Core/Ewide.Core.Arguments/Ewide.Core.DTO.csproj
@@ -9,9 +9,10 @@
Properties
Ewide.Core.Arguments
Ewide.Core.Arguments
- v4.5
+ v4.5.2
512
true
+
true
@@ -32,6 +33,7 @@
+
@@ -42,6 +44,7 @@
+
\ No newline at end of file
diff --git a/Api/Ewide.Core/Ewide.Core.Arguments/TestArgs.cs b/Api/Ewide.Core/Ewide.Core.Arguments/TestArgs.cs
new file mode 100644
index 0000000..7907a78
--- /dev/null
+++ b/Api/Ewide.Core/Ewide.Core.Arguments/TestArgs.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Ewide.Core.DTO
+{
+ public class TestArgs
+ {
+ [DisplayName("字段1")]
+ [Required(AllowEmptyStrings = false, ErrorMessage = "不可为空")]
+ public string TestFirst { get; set; }
+
+ [DisplayName("字段2")]
+ [RegularExpression(@"^[0-9]\d*$", ErrorMessage = "必须为数字")]
+ public int RegField { get; set; }
+
+ [Required]
+ [StringLength(int.MaxValue, MinimumLength = 5, ErrorMessage = "Name is exceeding the length limit")]
+ public string TestLength { get; set; }
+ }
+}
diff --git a/Api/Ewide.Core/Ewide.Core.Common/BaseDisplayJSON.cs b/Api/Ewide.Core/Ewide.Core.Common/BaseDisplayJSON.cs
index 84fc088..246188e 100644
--- a/Api/Ewide.Core/Ewide.Core.Common/BaseDisplayJSON.cs
+++ b/Api/Ewide.Core/Ewide.Core.Common/BaseDisplayJSON.cs
@@ -1,4 +1,5 @@
-using System;
+using Newtonsoft.Json;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
@@ -9,6 +10,17 @@ namespace Ewide.Core.Common
{
public class BaseDisplayJSON
{
+ public static object DisplayJSON(object obj)
+ {
+ var _result = JsonConvert.SerializeObject(obj, Formatting.Indented, new JsonSerializerSettings
+ {
+ ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver(),
+ DateFormatString = "yyyy-MM-dd HH:mm:ss"
+ });
+
+ return JsonConvert.DeserializeObject(_result);
+ }
+
public static object Display(HttpStatusCode status, object result)
{
return new
diff --git a/Api/Ewide.Core/Ewide.Core.Common/EnumCode/ResponseStatus.cs b/Api/Ewide.Core/Ewide.Core.Common/EnumCode/ResponseStatus.cs
deleted file mode 100644
index 497d43a..0000000
--- a/Api/Ewide.Core/Ewide.Core.Common/EnumCode/ResponseStatus.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Ewide.Core.Common
-{
- public enum ResponseStatus
- {
- // 权限验证失败
- Unauthorized = 401,
- // 未找到
- NotFound = 404,
- // 接口错误
- Error = 500,
- // 接口成功
- Success = 200
- }
-}
diff --git a/Api/Ewide.Core/Ewide.Core.Common/Ewide.Core.Common.csproj b/Api/Ewide.Core/Ewide.Core.Common/Ewide.Core.Common.csproj
index 472afe3..ccfecec 100644
--- a/Api/Ewide.Core/Ewide.Core.Common/Ewide.Core.Common.csproj
+++ b/Api/Ewide.Core/Ewide.Core.Common/Ewide.Core.Common.csproj
@@ -9,9 +9,10 @@
Properties
Ewide.Core.Common
Ewide.Core.Common
- v4.5
+ v4.5.2
512
true
+
true
@@ -31,6 +32,9 @@
4
+
+ ..\packages\Newtonsoft.Json.11.0.1\lib\net45\Newtonsoft.Json.dll
+
@@ -42,8 +46,13 @@
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Api/Ewide.Core/Ewide.Core.Common/packages.config b/Api/Ewide.Core/Ewide.Core.Common/packages.config
new file mode 100644
index 0000000..f7c9995
--- /dev/null
+++ b/Api/Ewide.Core/Ewide.Core.Common/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Api/Ewide.Core/Ewide.Core.Data/Dapper/CommandDefinition.cs b/Api/Ewide.Core/Ewide.Core.Data/Dapper/CommandDefinition.cs
new file mode 100644
index 0000000..1d65e08
--- /dev/null
+++ b/Api/Ewide.Core/Ewide.Core.Data/Dapper/CommandDefinition.cs
@@ -0,0 +1,187 @@
+using System;
+using System.Data;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Threading;
+
+namespace Dapper
+{
+ ///
+ /// Represents the key aspects of a sql operation
+ ///
+ public struct CommandDefinition
+ {
+ internal static CommandDefinition ForCallback(object parameters)
+ {
+ if (parameters is DynamicParameters)
+ {
+ return new CommandDefinition(parameters);
+ }
+ else
+ {
+ return default(CommandDefinition);
+ }
+ }
+
+ internal void OnCompleted()
+ {
+ (Parameters as SqlMapper.IParameterCallbacks)?.OnCompleted();
+ }
+
+ ///
+ /// The command (sql or a stored-procedure name) to execute
+ ///
+ public string CommandText { get; }
+
+ ///
+ /// The parameters associated with the command
+ ///
+ public object Parameters { get; }
+
+ ///
+ /// The active transaction for the command
+ ///
+ public IDbTransaction Transaction { get; }
+
+ ///
+ /// The effective timeout for the command
+ ///
+ public int? CommandTimeout { get; }
+
+ ///
+ /// The type of command that the command-text represents
+ ///
+ public CommandType? CommandType { get; }
+
+ ///
+ /// Should data be buffered before returning?
+ ///
+ public bool Buffered => (Flags & CommandFlags.Buffered) != 0;
+
+ ///
+ /// Should the plan for this query be cached?
+ ///
+ internal bool AddToCache => (Flags & CommandFlags.NoCache) == 0;
+
+ ///
+ /// Additional state flags against this command
+ ///
+ public CommandFlags Flags { get; }
+
+ ///
+ /// Can async queries be pipelined?
+ ///
+ public bool Pipelined => (Flags & CommandFlags.Pipelined) != 0;
+
+ ///
+ /// Initialize the command definition
+ ///
+ public CommandDefinition(string commandText, object parameters = null, IDbTransaction transaction = null, int? commandTimeout = null,
+ CommandType? commandType = null, CommandFlags flags = CommandFlags.Buffered
+#if ASYNC
+ , CancellationToken cancellationToken = default(CancellationToken)
+#endif
+ )
+ {
+ CommandText = commandText;
+ Parameters = parameters;
+ Transaction = transaction;
+ CommandTimeout = commandTimeout;
+ CommandType = commandType;
+ Flags = flags;
+#if ASYNC
+ CancellationToken = cancellationToken;
+#endif
+ }
+
+ private CommandDefinition(object parameters) : this()
+ {
+ Parameters = parameters;
+ }
+
+#if ASYNC
+
+ ///
+ /// For asynchronous operations, the cancellation-token
+ ///
+ public CancellationToken CancellationToken { get; }
+#endif
+
+ internal IDbCommand SetupCommand(IDbConnection cnn, Action paramReader)
+ {
+ var cmd = cnn.CreateCommand();
+ var init = GetInit(cmd.GetType());
+ init?.Invoke(cmd);
+ if (Transaction != null)
+ cmd.Transaction = Transaction;
+ cmd.CommandText = CommandText;
+ if (CommandTimeout.HasValue)
+ {
+ cmd.CommandTimeout = CommandTimeout.Value;
+ }
+ else if (SqlMapper.Settings.CommandTimeout.HasValue)
+ {
+ cmd.CommandTimeout = SqlMapper.Settings.CommandTimeout.Value;
+ }
+ if (CommandType.HasValue)
+ cmd.CommandType = CommandType.Value;
+ paramReader?.Invoke(cmd, Parameters);
+ return cmd;
+ }
+
+ private static SqlMapper.Link> commandInitCache;
+
+ private static Action GetInit(Type commandType)
+ {
+ if (commandType == null)
+ return null; // GIGO
+ Action action;
+ if (SqlMapper.Link>.TryGet(commandInitCache, commandType, out action))
+ {
+ return action;
+ }
+ var bindByName = GetBasicPropertySetter(commandType, "BindByName", typeof(bool));
+ var initialLongFetchSize = GetBasicPropertySetter(commandType, "InitialLONGFetchSize", typeof(int));
+
+ action = null;
+ if (bindByName != null || initialLongFetchSize != null)
+ {
+ var method = new DynamicMethod(commandType.Name + "_init", null, new Type[] { typeof(IDbCommand) });
+ var il = method.GetILGenerator();
+
+ if (bindByName != null)
+ {
+ // .BindByName = true
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Castclass, commandType);
+ il.Emit(OpCodes.Ldc_I4_1);
+ il.EmitCall(OpCodes.Callvirt, bindByName, null);
+ }
+ if (initialLongFetchSize != null)
+ {
+ // .InitialLONGFetchSize = -1
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Castclass, commandType);
+ il.Emit(OpCodes.Ldc_I4_M1);
+ il.EmitCall(OpCodes.Callvirt, initialLongFetchSize, null);
+ }
+ il.Emit(OpCodes.Ret);
+ action = (Action)method.CreateDelegate(typeof(Action));
+ }
+ // cache it
+ SqlMapper.Link>.TryAdd(ref commandInitCache, commandType, ref action);
+ return action;
+ }
+
+ private static MethodInfo GetBasicPropertySetter(Type declaringType, string name, Type expectedType)
+ {
+ var prop = declaringType.GetProperty(name, BindingFlags.Public | BindingFlags.Instance);
+ if (prop != null && prop.CanWrite && prop.PropertyType == expectedType && prop.GetIndexParameters().Length == 0)
+ {
+ return prop.GetSetMethod();
+ }
+ return null;
+ }
+ }
+
+}
diff --git a/Api/Ewide.Core/Ewide.Core.Data/Dapper/CommandFlags.cs b/Api/Ewide.Core/Ewide.Core.Data/Dapper/CommandFlags.cs
new file mode 100644
index 0000000..e2589c7
--- /dev/null
+++ b/Api/Ewide.Core/Ewide.Core.Data/Dapper/CommandFlags.cs
@@ -0,0 +1,30 @@
+using System;
+
+namespace Dapper
+{
+
+ ///
+ /// Additional state flags that control command behaviour
+ ///
+ [Flags]
+ public enum CommandFlags
+ {
+ ///
+ /// No additional flags
+ ///
+ None = 0,
+ ///
+ /// Should data be buffered before returning?
+ ///
+ Buffered = 1,
+ ///
+ /// Can async queries be pipelined?
+ ///
+ Pipelined = 2,
+ ///
+ /// Should the plan cache be bypassed?
+ ///
+ NoCache = 4,
+ }
+
+}
diff --git a/Api/Ewide.Core/Ewide.Core.Data/Dapper/CustomPropertyTypeMap.cs b/Api/Ewide.Core/Ewide.Core.Data/Dapper/CustomPropertyTypeMap.cs
new file mode 100644
index 0000000..a1eba87
--- /dev/null
+++ b/Api/Ewide.Core/Ewide.Core.Data/Dapper/CustomPropertyTypeMap.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Reflection;
+
+namespace Dapper
+{
+
+ ///
+ /// Implements custom property mapping by user provided criteria (usually presence of some custom attribute with column to member mapping)
+ ///
+ public sealed class CustomPropertyTypeMap : SqlMapper.ITypeMap
+ {
+ private readonly Type _type;
+ private readonly Func _propertySelector;
+
+ ///
+ /// Creates custom property mapping
+ ///
+ /// Target entity type
+ /// Property selector based on target type and DataReader column name
+ public CustomPropertyTypeMap(Type type, Func propertySelector)
+ {
+ if (type == null)
+ throw new ArgumentNullException(nameof(type));
+
+ if (propertySelector == null)
+ throw new ArgumentNullException(nameof(propertySelector));
+
+ _type = type;
+ _propertySelector = propertySelector;
+ }
+
+ ///
+ /// Always returns default constructor
+ ///
+ /// DataReader column names
+ /// DataReader column types
+ /// Default constructor
+ public ConstructorInfo FindConstructor(string[] names, Type[] types)
+ {
+ return _type.GetConstructor(new Type[0]);
+ }
+
+ ///
+ /// Always returns null
+ ///
+ ///
+ public ConstructorInfo FindExplicitConstructor()
+ {
+ return null;
+ }
+
+ ///
+ /// Not implemented as far as default constructor used for all cases
+ ///
+ ///
+ ///
+ ///
+ public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor, string columnName)
+ {
+ throw new NotSupportedException();
+ }
+
+ ///
+ /// Returns property based on selector strategy
+ ///
+ /// DataReader column name
+ /// Poperty member map
+ public SqlMapper.IMemberMap GetMember(string columnName)
+ {
+ var prop = _propertySelector(_type, columnName);
+ return prop != null ? new SimpleMemberMap(columnName, prop) : null;
+ }
+ }
+}
diff --git a/Api/Ewide.Core/Ewide.Core.Data/Dapper/DataTableHandler.cs b/Api/Ewide.Core/Ewide.Core.Data/Dapper/DataTableHandler.cs
new file mode 100644
index 0000000..2e2472e
--- /dev/null
+++ b/Api/Ewide.Core/Ewide.Core.Data/Dapper/DataTableHandler.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Data;
+#if !COREFX
+namespace Dapper
+{
+ sealed class DataTableHandler : SqlMapper.ITypeHandler
+ {
+ public object Parse(Type destinationType, object value)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void SetValue(IDbDataParameter parameter, object value)
+ {
+ TableValuedParameter.Set(parameter, value as DataTable, null);
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Api/Ewide.Core/Ewide.Core.Data/Dapper/DbString.cs b/Api/Ewide.Core/Ewide.Core.Data/Dapper/DbString.cs
new file mode 100644
index 0000000..cd57347
--- /dev/null
+++ b/Api/Ewide.Core/Ewide.Core.Data/Dapper/DbString.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Data;
+
+namespace Dapper
+{
+ ///
+ /// This class represents a SQL string, it can be used if you need to denote your parameter is a Char vs VarChar vs nVarChar vs nChar
+ ///
+ public sealed class DbString : SqlMapper.ICustomQueryParameter
+ {
+ ///
+ /// Default value for IsAnsi.
+ ///
+ public static bool IsAnsiDefault { get; set; }
+
+ ///
+ /// A value to set the default value of strings
+ /// going through Dapper. Default is 4000, any value larger than this
+ /// field will not have the default value applied.
+ ///
+ public const int DefaultLength = 4000;
+
+ ///
+ /// Create a new DbString
+ ///
+ public DbString()
+ {
+ Length = -1;
+ IsAnsi = IsAnsiDefault;
+ }
+ ///
+ /// Ansi vs Unicode
+ ///
+ public bool IsAnsi { get; set; }
+ ///
+ /// Fixed length
+ ///
+ public bool IsFixedLength { get; set; }
+ ///
+ /// Length of the string -1 for max
+ ///
+ public int Length { get; set; }
+ ///
+ /// The value of the string
+ ///
+ public string Value { get; set; }
+ ///
+ /// Add the parameter to the command... internal use only
+ ///
+ ///
+ ///
+ public void AddParameter(IDbCommand command, string name)
+ {
+ if (IsFixedLength && Length == -1)
+ {
+ throw new InvalidOperationException("If specifying IsFixedLength, a Length must also be specified");
+ }
+ var param = command.CreateParameter();
+ param.ParameterName = name;
+#pragma warning disable 0618
+ param.Value = SqlMapper.SanitizeParameterValue(Value);
+#pragma warning restore 0618
+ if (Length == -1 && Value != null && Value.Length <= DefaultLength)
+ {
+ param.Size = DefaultLength;
+ }
+ else
+ {
+ param.Size = Length;
+ }
+ param.DbType = IsAnsi ? (IsFixedLength ? DbType.AnsiStringFixedLength : DbType.AnsiString) : (IsFixedLength ? DbType.StringFixedLength : DbType.String);
+ command.Parameters.Add(param);
+ }
+ }
+}
diff --git a/Api/Ewide.Core/Ewide.Core.Data/Dapper/DefaultTypeMap.cs b/Api/Ewide.Core/Ewide.Core.Data/Dapper/DefaultTypeMap.cs
new file mode 100644
index 0000000..cd24607
--- /dev/null
+++ b/Api/Ewide.Core/Ewide.Core.Data/Dapper/DefaultTypeMap.cs
@@ -0,0 +1,203 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+namespace Dapper
+{
+ ///
+ /// Represents default type mapping strategy used by Dapper
+ ///
+ public sealed class DefaultTypeMap : SqlMapper.ITypeMap
+ {
+ private readonly List _fields;
+ private readonly Type _type;
+
+ ///
+ /// Creates default type map
+ ///
+ /// Entity type
+ public DefaultTypeMap(Type type)
+ {
+ if (type == null)
+ throw new ArgumentNullException(nameof(type));
+
+ _fields = GetSettableFields(type);
+ Properties = GetSettableProps(type);
+ _type = type;
+ }
+#if COREFX
+ static bool IsParameterMatch(ParameterInfo[] x, ParameterInfo[] y)
+ {
+ if (ReferenceEquals(x, y)) return true;
+ if (x == null || y == null) return false;
+ if (x.Length != y.Length) return false;
+ for (int i = 0; i < x.Length; i++)
+ if (x[i].ParameterType != y[i].ParameterType) return false;
+ return true;
+ }
+#endif
+ internal static MethodInfo GetPropertySetter(PropertyInfo propertyInfo, Type type)
+ {
+ if (propertyInfo.DeclaringType == type) return propertyInfo.GetSetMethod(true);
+#if COREFX
+ return propertyInfo.DeclaringType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
+ .Single(x => x.Name == propertyInfo.Name
+ && x.PropertyType == propertyInfo.PropertyType
+ && IsParameterMatch(x.GetIndexParameters(), propertyInfo.GetIndexParameters())
+ ).GetSetMethod(true);
+#else
+ return propertyInfo.DeclaringType.GetProperty(
+ propertyInfo.Name,
+ BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
+ Type.DefaultBinder,
+ propertyInfo.PropertyType,
+ propertyInfo.GetIndexParameters().Select(p => p.ParameterType).ToArray(),
+ null).GetSetMethod(true);
+#endif
+ }
+
+ internal static List GetSettableProps(Type t)
+ {
+ return t
+ .GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
+ .Where(p => GetPropertySetter(p, t) != null)
+ .ToList();
+ }
+
+ internal static List GetSettableFields(Type t)
+ {
+ return t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).ToList();
+ }
+
+ ///
+ /// Finds best constructor
+ ///
+ /// DataReader column names
+ /// DataReader column types
+ /// Matching constructor or default one
+ public ConstructorInfo FindConstructor(string[] names, Type[] types)
+ {
+ var constructors = _type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+ foreach (ConstructorInfo ctor in constructors.OrderBy(c => c.IsPublic ? 0 : (c.IsPrivate ? 2 : 1)).ThenBy(c => c.GetParameters().Length))
+ {
+ ParameterInfo[] ctorParameters = ctor.GetParameters();
+ if (ctorParameters.Length == 0)
+ return ctor;
+
+ if (ctorParameters.Length != types.Length)
+ continue;
+
+ int i = 0;
+ for (; i < ctorParameters.Length; i++)
+ {
+ if (!String.Equals(ctorParameters[i].Name, names[i], StringComparison.OrdinalIgnoreCase))
+ break;
+ if (types[i] == typeof(byte[]) && ctorParameters[i].ParameterType.FullName == SqlMapper.LinqBinary)
+ continue;
+ var unboxedType = Nullable.GetUnderlyingType(ctorParameters[i].ParameterType) ?? ctorParameters[i].ParameterType;
+ if ((unboxedType != types[i] && !SqlMapper.HasTypeHandler(unboxedType))
+ && !(unboxedType.IsEnum() && Enum.GetUnderlyingType(unboxedType) == types[i])
+ && !(unboxedType == typeof(char) && types[i] == typeof(string))
+ && !(unboxedType.IsEnum() && types[i] == typeof(string)))
+ {
+ break;
+ }
+ }
+
+ if (i == ctorParameters.Length)
+ return ctor;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Returns the constructor, if any, that has the ExplicitConstructorAttribute on it.
+ ///
+ public ConstructorInfo FindExplicitConstructor()
+ {
+ var constructors = _type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+#if COREFX
+ var withAttr = constructors.Where(c => c.CustomAttributes.Any(x => x.AttributeType == typeof(ExplicitConstructorAttribute))).ToList();
+#else
+ var withAttr = constructors.Where(c => c.GetCustomAttributes(typeof(ExplicitConstructorAttribute), true).Length > 0).ToList();
+#endif
+
+ if (withAttr.Count == 1)
+ {
+ return withAttr[0];
+ }
+
+ return null;
+ }
+
+ ///
+ /// Gets mapping for constructor parameter
+ ///
+ /// Constructor to resolve
+ /// DataReader column name
+ /// Mapping implementation
+ public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor, string columnName)
+ {
+ var parameters = constructor.GetParameters();
+
+ return new SimpleMemberMap(columnName, parameters.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase)));
+ }
+
+ ///
+ /// Gets member mapping for column
+ ///
+ /// DataReader column name
+ /// Mapping implementation
+ public SqlMapper.IMemberMap GetMember(string columnName)
+ {
+ var property = Properties.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.Ordinal))
+ ?? Properties.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase));
+
+ if (property == null && MatchNamesWithUnderscores)
+ {
+ property = Properties.FirstOrDefault(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.Ordinal))
+ ?? Properties.FirstOrDefault(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.OrdinalIgnoreCase));
+ }
+
+ if (property != null)
+ return new SimpleMemberMap(columnName, property);
+
+ // roslyn automatically implemented properties, in particular for get-only properties: <{Name}>k__BackingField;
+ var backingFieldName = "<" + columnName + ">k__BackingField";
+
+ // preference order is:
+ // exact match over underscre match, exact case over wrong case, backing fields over regular fields, match-inc-underscores over match-exc-underscores
+ var field = _fields.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.Ordinal))
+ ?? _fields.FirstOrDefault(p => string.Equals(p.Name, backingFieldName, StringComparison.Ordinal))
+ ?? _fields.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase))
+ ?? _fields.FirstOrDefault(p => string.Equals(p.Name, backingFieldName, StringComparison.OrdinalIgnoreCase));
+
+ if (field == null && MatchNamesWithUnderscores)
+ {
+ var effectiveColumnName = columnName.Replace("_", "");
+ backingFieldName = "<" +effectiveColumnName + ">k__BackingField";
+
+ field = _fields.FirstOrDefault(p => string.Equals(p.Name, effectiveColumnName, StringComparison.Ordinal))
+ ?? _fields.FirstOrDefault(p => string.Equals(p.Name, backingFieldName, StringComparison.Ordinal))
+ ?? _fields.FirstOrDefault(p => string.Equals(p.Name, effectiveColumnName, StringComparison.OrdinalIgnoreCase))
+ ?? _fields.FirstOrDefault(p => string.Equals(p.Name, backingFieldName, StringComparison.OrdinalIgnoreCase));
+ }
+
+ if (field != null)
+ return new SimpleMemberMap(columnName, field);
+
+ return null;
+ }
+ ///
+ /// Should column names like User_Id be allowed to match properties/fields like UserId ?
+ ///
+ public static bool MatchNamesWithUnderscores { get; set; }
+
+ ///
+ /// The settable properties for this typemap
+ ///
+ public List Properties { get; }
+ }
+}
diff --git a/Api/Ewide.Core/Ewide.Core.Data/Dapper/DynamicParameters.CachedOutputSetters.cs b/Api/Ewide.Core/Ewide.Core.Data/Dapper/DynamicParameters.CachedOutputSetters.cs
new file mode 100644
index 0000000..e7697c6
--- /dev/null
+++ b/Api/Ewide.Core/Ewide.Core.Data/Dapper/DynamicParameters.CachedOutputSetters.cs
@@ -0,0 +1,16 @@
+using System.Collections;
+
+namespace Dapper
+{
+ partial class DynamicParameters
+ {
+ // The type here is used to differentiate the cache by type via generics
+ // ReSharper disable once UnusedTypeParameter
+ internal static class CachedOutputSetters
+ {
+ // Intentional, abusing generics to get our cache splits
+ // ReSharper disable once StaticMemberInGenericType
+ public static readonly Hashtable Cache = new Hashtable();
+ }
+ }
+}
diff --git a/Api/Ewide.Core/Ewide.Core.Data/Dapper/DynamicParameters.ParamInfo.cs b/Api/Ewide.Core/Ewide.Core.Data/Dapper/DynamicParameters.ParamInfo.cs
new file mode 100644
index 0000000..e323cae
--- /dev/null
+++ b/Api/Ewide.Core/Ewide.Core.Data/Dapper/DynamicParameters.ParamInfo.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Data;
+
+namespace Dapper
+{
+ partial class DynamicParameters
+ {
+ sealed class ParamInfo
+ {
+ public string Name { get; set; }
+ public object Value { get; set; }
+ public ParameterDirection ParameterDirection { get; set; }
+ public DbType? DbType { get; set; }
+ public int? Size { get; set; }
+ public IDbDataParameter AttachedParam { get; set; }
+ internal Action