public virtual void ProcessDeleteRequest <T>(CommandDefinition <T> commandDefinition) where T : class
        {
            var type             = CheckCommandConditions(commandDefinition, "delete");
            var entityTypeResult = EntityCache.GetEntity(type) ?? TypeAnalyzer.AnalyzeType(type);
            var keyColumns       = GetKeyColumns(type);

            if (!keyColumns.Any())
            {
                throw new ArgumentException("At least one key column property must be defined.");
            }

            var sql        = new StringBuilder();
            var parameters = new List <KeyValuePair <string, object> >();

            sql.Append("DELETE FROM ");
            sql.AppendLine(entityTypeResult.TableName);
            AppendWhereCondition(new WhereCondition
            {
                Query      = sql,
                TableName  = entityTypeResult.TableName,
                Parameters = parameters,
                Properties = keyColumns
            },
                                 commandDefinition.Entity);

            commandDefinition.UpdateCommand(sql.ToString(), parameters);
        }
        public virtual void ProcessQueryEntityRequest <T>(CommandDefinition <T> commandDefinition, object id) where T : class
        {
            var keyColumns = GetKeyColumns(typeof(T));

            if (keyColumns.Count() == 0)
            {
                throw new NotSupportedException("No key columns available");
            }

            if (id == null ||
                id.GetType().ImplementsIEnumerable() ||
                (keyColumns.Count() == 1 && !id.GetType().IsNoClass()) ||
                (keyColumns.Count() > 1 && !id.GetType().IsClass()))
            {
                throw new ArgumentException("Invalid id value");
            }

            var query      = $"SELECT * FROM {TypeAnalyzer.GetTableName<T>()}";
            var parameters = new List <KeyValuePair <string, object> >();

            if (keyColumns.Count() == 1)
            {
                var keyColumn = keyColumns.First();
                query += $" WHERE {keyColumn.ColumnName} = @{keyColumn.PropertyInfo.Name}";
                parameters.Add(new KeyValuePair <string, object>(keyColumn.PropertyInfo.Name, id));
            }
            else
            {
                var firstColumn = true;
                foreach (var keyColumn in keyColumns)
                {
                    var propertyValue = id.GetType().GetProperty(keyColumn.PropertyInfo.Name).GetValue(id);
                    parameters.Add(new KeyValuePair <string, object>(keyColumn.PropertyInfo.Name, propertyValue));

                    var prefix = firstColumn ? "WHERE" : "AND";
                    query      += $" {prefix} {keyColumn.ColumnName} = @{keyColumn.PropertyInfo.Name}";
                    firstColumn = false;
                }
            }

            commandDefinition.UpdateCommand(query, parameters);
        }
        public virtual void ProcessInsertRequest <T>(CommandDefinition <T> commandDefinition) where T : class
        {
            var type = CheckCommandConditions(commandDefinition, "insert");

            var entityTypeResult = EntityCache.GetEntity(type) ?? TypeAnalyzer.AnalyzeType(type);

            if (!entityTypeResult.HasPrimaryKey())
            {
                throw new ArgumentException("At least one key column property must be defined.");
            }

            var properties = GetProperties(new PropertyRequest
            {
                Type   = type,
                Entity = commandDefinition.Entity
            });


            var sql        = new StringBuilder();
            var sqlColumns = new StringBuilder();
            var sqlValues  = new StringBuilder();

            var parameters  = new List <KeyValuePair <string, object> >();
            var firstColumn = true;

            foreach (var property in properties)
            {
                if (firstColumn)
                {
                    firstColumn = false;
                }
                else
                {
                    sqlColumns.Append(",");
                    sqlValues.Append(",");
                }

                sqlColumns.Append($"[");
                sqlValues.Append("@");
                if (!property.Prefix.IsNullOrEmpty())
                {
                    sqlColumns.Append(property.Prefix);
                    sqlValues.Append(property.Prefix);
                }

                sqlColumns.Append($"{property.ColumnName}]");
                sqlValues.Append(property.PropertyInfo.Name);

                parameters.Add(new KeyValuePair <string, object>($"{property.Prefix}{property.PropertyInfo.Name}", property.PropertyInfo.GetValue(property.Entity)));
            }

            sql.Append("INSERT INTO ");
            sql.Append(entityTypeResult.TableName);
            sql.Append("(");
            sql.Append(sqlColumns.ToString());
            sql.AppendLine(")");
            sql.Append("VALUES (");
            sql.Append(sqlValues.ToString());
            sql.AppendLine(");");

            if (entityTypeResult.HasAutoGeneratedPrimaryKey())
            {
                sql.AppendLine(GetLastInsertedPrimaryKeyQuery());
            }
            else
            {
                sql.Append("SELECT @");
                sql.Append(entityTypeResult.GetFirstPrimaryKey().Name);
                sql.AppendLine(";");
            }

            commandDefinition.UpdateCommand(sql.ToString(), parameters);
        }
        public virtual void ProcessUpdateRequest <T>(CommandDefinition <T> commandDefinition, object partialEntity = null, IEnumerable <KeyValuePair <string, object> > patchProperties = null) where T : class
        {
            var type = CheckCommandConditions(commandDefinition, "update", partialEntity, patchProperties);

            var entityTypeResult = EntityCache.GetEntity(type) ?? TypeAnalyzer.AnalyzeType(type);
            var keyColumns       = GetKeyColumns(type, partialEntity?.GetType(), patchProperties?.Select(p => p.Key).ToList());

            if (!keyColumns.Any())
            {
                throw new ArgumentException("At least one key column property must be defined.");
            }

            if (partialEntity != default || patchProperties != default)
            {
                commandDefinition.Entity = ObjectGenerator.CreateEmptyInstance <T>();
            }

            var properties = GetProperties(new PropertyRequest
            {
                Type            = type,
                Entity          = commandDefinition.Entity,
                PartialEntity   = partialEntity,
                PatchProperties = patchProperties
            });

            var sql        = new StringBuilder();
            var parameters = new List <KeyValuePair <string, object> >();

            sql.Append("UPDATE ");
            sql.AppendLine(entityTypeResult.TableName);
            sql.AppendLine(" SET");

            var firstColumn = true;

            foreach (var property in properties)
            {
                if (SkipPropertyForUpdate(property, keyColumns))
                {
                    continue;
                }

                sql.Append("\t");
                if (firstColumn)
                {
                    firstColumn = false;
                    sql.Append(" ");
                }
                else
                {
                    sql.Append(",");
                }

                sql.Append($"[");
                if (!property.Prefix.IsNullOrEmpty())
                {
                    sql.Append(property.Prefix);
                }

                sql.Append($"{property.ColumnName}]");
                sql.Append(" = @");

                if (!property.Prefix.IsNullOrEmpty())
                {
                    sql.Append(property.Prefix);
                }

                if (property.PropertyInfo == default && property.Entity?.GetType() == _patchPropertyType)
                {
                    sql.AppendLine(property.ColumnName);
                    parameters.Add(new KeyValuePair <string, object>($"{property.Prefix}{property.ColumnName}", ((KeyValuePair <string, object>)property.Entity).Value));

                    continue;
                }

                sql.AppendLine(property.PropertyInfo?.Name);
                parameters.Add(new KeyValuePair <string, object>($"{property.Prefix}{property.PropertyInfo.Name}", property.PropertyInfo.GetValue(property.Entity)));
            }

            AppendWhereCondition(new WhereCondition
            {
                Query      = sql,
                TableName  = entityTypeResult.TableName,
                Parameters = parameters,
                Properties = keyColumns
            },
                                 partialEntity ?? commandDefinition.Entity,
                                 patchProperties);

            commandDefinition.UpdateCommand(sql.ToString(), parameters);
        }