using System; using System.Collections.Generic; using System.Data; using System.Linq; using Dapper; using Oracle.ManagedDataAccess.Client; namespace Host.Repositories { internal class OracleDynamicParameters { private static Dictionary> paramReaderCache = new Dictionary>(); private Dictionary parameters = new Dictionary(); private List templates; private class ParamInfo { public string Name { get; set; } public object Value { get; set; } public ParameterDirection ParameterDirection { get; set; } public OracleDbType? DbType { get; set; } public int? Size { get; set; } public IDbDataParameter AttachedParam { get; set; } } /// /// construct a dynamic parameter bag /// public OracleDynamicParameters() { } /// /// construct a dynamic parameter bag /// /// can be an anonymous type or a DynamicParameters bag public OracleDynamicParameters(object template) { AddDynamicParams(template); } /// /// Append a whole object full of params to the dynamic /// EG: AddDynamicParams(new {A = 1, B = 2}) // will add property A and B to the dynamic /// /// public void AddDynamicParams( #if CSHARP30 object param #else dynamic param #endif ) { var obj = param as object; if (obj != null) { var subDynamic = obj as OracleDynamicParameters; if (subDynamic == null) { var dictionary = obj as IEnumerable>; if (dictionary == null) { templates = templates ?? new List(); templates.Add(obj); } else { foreach (var kvp in dictionary) { #if CSHARP30 Add(kvp.Key, kvp.Value, null, null, null); #else Add(kvp.Key, kvp.Value); #endif } } } else { if (subDynamic.parameters != null) { foreach (var kvp in subDynamic.parameters) { parameters.Add(kvp.Key, kvp.Value); } } if (subDynamic.templates != null) { templates = templates ?? new List(); foreach (var t in subDynamic.templates) { templates.Add(t); } } } } } /// /// Add a parameter to this dynamic parameter list /// /// /// /// /// /// public void Add( #if CSHARP30 string name, object value, DbType? dbType, ParameterDirection? direction, int? size #else string name, object value = null, OracleDbType? dbType = null, ParameterDirection? direction = null, int? size = null #endif ) { parameters[Clean(name)] = new ParamInfo() { Name = name, Value = value, ParameterDirection = direction ?? ParameterDirection.Input, DbType = dbType, Size = size }; } private static string Clean(string name) { if (!string.IsNullOrEmpty(name)) { switch (name[0]) { case '@': case ':': case '?': return name.Substring(1); } } return name; } /// /// Add all the parameters needed to the command just before it executes /// /// The raw command prior to execution /// Information about the query protected void AddParameters(IDbCommand command, SqlMapper.Identity identity) { if (templates != null) { foreach (var template in templates) { var newIdent = identity.ForDynamicParameters(template.GetType()); Action appender; lock (paramReaderCache) { if (!paramReaderCache.TryGetValue(newIdent, out appender)) { appender = SqlMapper.CreateParamInfoGenerator(newIdent, false, false); paramReaderCache[newIdent] = appender; } } appender(command, template); } } foreach (var param in parameters.Values) { string name = Clean(param.Name); bool add = !((OracleCommand)command).Parameters.Contains(name); OracleParameter p; if (add) { p = ((OracleCommand)command).CreateParameter(); p.ParameterName = name; } else { p = ((OracleCommand)command).Parameters[name]; } var val = param.Value; p.Value = val ?? DBNull.Value; p.Direction = param.ParameterDirection; var s = val as string; if (s != null) { if (s.Length <= 4000) { p.Size = 4000; } } if (param.Size != null) { p.Size = param.Size.Value; } if (param.DbType != null) { p.OracleDbType = param.DbType.Value; } if (add) { command.Parameters.Add(p); } param.AttachedParam = p; } } /// /// All the names of the param in the bag, use Get to yank them out /// public IEnumerable ParameterNames { get { return parameters.Select(p => p.Key); } } /// /// Get the value of a parameter /// /// /// /// The value, note DBNull.Value is not returned, instead the value is returned as null public T Get(string name) { var val = parameters[Clean(name)].AttachedParam.Value; if (val == DBNull.Value) { if (default(T) != null) { throw new ApplicationException("Attempting to cast a DBNull to a non nullable type!"); } return default(T); } return (T)val; } } }