private static CommandInfo InitCommand(DapperAccessLayer layer, MethodInfo method)
        {
            CommandAttribute attr = method.GetCustomAttributes(typeof(CommandAttribute), false).Cast <CommandAttribute>().Single();

            CommandInfo info = new CommandInfo()
            {
                Attribute      = attr,
                TimeoutSeconds = attr.CommandTimeout > 0 ? attr.CommandTimeout : (int?)null
            };

            // Find all method parameters that shall be wrapped by runtime DTO type
            PropertyDefinition[] properties = method.GetParameters()
                                              .Where(p => IsDatabaseType(p.ParameterType))
                                              .Select(p => new PropertyDefinition(p.Name, p.ParameterType))
                                              .ToArray();

            // If any, create runtime dto type
            if (properties.Length > 0)
            {
                // First create an interface definining the properties
                string interfaceTypeName = method.DeclaringType.FullName.Replace('+', '_') + "." + method.Name + "_" + method.GetHashCode().ToString();
                Type   interfaceType     = s_Factory.Module.Assembly.GetType(interfaceTypeName);
                if (interfaceType == null)
                {
                    interfaceType = s_Factory.Module.DefineInterface(interfaceTypeName, null, properties);
                }

                // Then implement that by runtime dto type
                info.ParameterType           = s_ParameterFactory.Implement(interfaceType);
                info.ParameterTypeProperties = info.ParameterType.GetProperties();
            }

            return(info);
        }
        protected static object ExecNonQuery(DapperAccessLayer layer, CommandInfo info, object[] parameters)
        {
            // Define how to execute on open connection
            Func <IDbConnection, object, object> exec = (connection, parameter) =>
            {
                // Let Dapper do the hard work
                return(connection.Execute(info.Attribute.CommandText, parameter, null, info.TimeoutSeconds, info.Attribute.CommandType));
            };

            return(ExecCommand(layer, info, parameters, exec));
        }
        /// <summary>
        /// Called once for each interface method when runtime class instance is created.
        /// </summary>
        /// <param name="layer"></param>
        /// <param name="method"></param>
        /// <returns></returns>
        protected static CommandInfo InitQuery(DapperAccessLayer layer, MethodInfo method)
        {
            CommandInfo info = InitCommand(layer, method);

            // Extract row type from signature and create specialized execute method
            Type       rowType    = method.ReturnType.GetGenericArguments().Single();
            MethodInfo execMethod = s_ExecCommandMethod.MakeGenericMethod(rowType);

            info.ExecQuery = (Func <DapperAccessLayer, CommandInfo, object[], object>)Delegate.CreateDelegate(typeof(Func <DapperAccessLayer, CommandInfo, object[], object>), execMethod);

            return(info);
        }
        private static object ExecQueryGeneric <T>(DapperAccessLayer layer, CommandInfo info, object[] parameters)
        {
            // See if we shall read lazy or not
            bool buffered = ((QueryAttribute)info.Attribute).Buffered;

            // Define how to execute on open connection
            Func <IDbConnection, object, object> exec = (connection, parameter) =>
            {
                // Let Dapper do the hard work
                return(connection.Query <T>(info.Attribute.CommandText, parameter, buffered: buffered, commandType: info.Attribute.CommandType, commandTimeout: info.TimeoutSeconds));
            };

            return(ExecCommand(layer, info, parameters, exec));
        }
        private static object ExecCommand(DapperAccessLayer layer, CommandInfo info, object[] parameters, Func <IDbConnection, object, object> command)
        {
            // Make sure we have an open connection
            IDbConnection con   = layer._connectionFactory();
            bool          close = con.State != ConnectionState.Open;

            if (close)
            {
                con.Open();
            }

            try
            {
                // Default is to use DTO provided as single param to interface method (the Dapper style)
                object parameter = parameters.FirstOrDefault();

                // If we're using runtime dto type, create instance of it and set properties from method parameters
                if (info.ParameterType != null)
                {
                    parameter = Activator.CreateInstance(info.ParameterType);
                    for (int i = 0; i < info.ParameterTypeProperties.Length; i++)
                    {
                        info.ParameterTypeProperties[i].SetValue(parameter, parameters[i], null);
                    }
                }

                return(command(con, parameter));
            }
            finally
            {
                if (close)
                {
                    con.Close();
                }
            }
        }
 protected static CommandInfo InitNonQuery(DapperAccessLayer layer, MethodInfo method)
 {
     return(InitCommand(layer, method));
 }
 /// <summary>
 /// Called whenever interface method is executed.
 /// </summary>
 /// <param name="layer"></param>
 /// <param name="info"></param>
 /// <param name="parameters"></param>
 /// <returns></returns>
 protected static object ExecQuery(DapperAccessLayer layer, CommandInfo info, object[] parameters)
 {
     // Execute in specialized generic method to be able to call Dapper query
     return(info.ExecQuery(layer, info, parameters));
 }