//No setea valores null
        //Si se modifico la pk aunque sea natural no la updatea (usea ignora la pk)
        private void update(Serializable objeto, String primaryKeyPropertyName, String tableName, bool cascadeMode)
        {
            String updateQuery = "update " + tableName + " set ";

            List <SqlParameter> parametros = new List <SqlParameter>();

            Dictionary <string, object> propertyValues = getPropertyValues(objeto);

            foreach (KeyValuePair <string, object> keyValuePair in propertyValues)
            {
                if (keyValuePair.Key != primaryKeyPropertyName)
                {
                    String dataName = objeto.getMapFromKey(keyValuePair.Key);

                    if (dataName != "")
                    {
                        bool isSerializableProperty = typeof(Serializable).IsAssignableFrom(keyValuePair.Value.GetType());

                        object parametro = keyValuePair.Value;

                        if (isSerializableProperty)
                        {
                            Serializable serializableProperty = (Serializable)keyValuePair.Value;

                            parametro = serializableProperty.getPropertyValue(serializableProperty.getIdPropertyName());
                        }
                        updateQuery += dataName + "=@" + dataName + ",";
                        DataBase.Instance.agregarParametro(parametros, "@" + dataName, parametro);
                    }
                }
            }

            updateQuery = updateQuery.Remove(updateQuery.Length - 1);

            updateQuery += " where " + objeto.getMapFromKey(primaryKeyPropertyName) + "="
                           + objeto.getPkValue();

            if (cascadeMode)
            {
                List <String> serializablePropertyNames = listSerializableProperties(objeto);

                foreach (KeyValuePair <string, object> keyValuePair in propertyValues)
                {
                    //Aca supongo que no puede ser null
                    if (serializablePropertyNames.Contains(keyValuePair.Key))
                    {
                        Serializable serializableProperty = (Serializable)keyValuePair.Value;

                        update(serializableProperty, serializableProperty.getIdPropertyName(), serializableProperty.getTableName(), cascadeMode);
                    }
                }
            }

            DataBase.Instance.ejecutarConsulta(updateQuery, parametros);

            foreach (var item in objeto.getOneToManyPropertyNames())
            {
                updateOneToManyProperty(objeto, item, cascadeMode);
            }
        }
        private void delete(Serializable objeto, String primaryKeyPropertyName, String tableName)
        {
            List <SqlParameter> parameters = new List <SqlParameter>();

            string expected = "@" + objeto.getMapFromKey(primaryKeyPropertyName);

            DataBase.Instance.agregarParametro(parameters, expected, objeto.getPkValue());

            String deleteQuery = "delete from " + tableName + " where "
                                 + objeto.getMapFromKey(primaryKeyPropertyName) + "="
                                 + expected;

            DataBase.Instance.ejecutarConsulta(deleteQuery, parameters);
        }
        internal IList selectByProperties(Dictionary <string, object> properties, Type classType)
        {
            Serializable objeto = (Serializable)Activator.CreateInstance(classType);

            List <SqlParameter> parameters = new List <SqlParameter>();

            string selectQuery = "select * from " + objeto.getTableName() + " where ";

            foreach (KeyValuePair <string, object> property in properties)
            {
                string expected        = "@" + objeto.getMapFromKey(property.Key);
                object pkPropertyValue = typeof(Serializable).IsAssignableFrom(property.Value.GetType()) ? ((Serializable)property.Value).getPkValue() : property.Value;

                DataBase.Instance.agregarParametro(parameters, expected, pkPropertyValue);
                selectQuery += objeto.getMapFromKey(property.Key) + "=" + expected + " and ";
            }

            selectQuery = selectQuery.Remove(selectQuery.Length - 5);

            return(executeAutoMappedSelect(selectQuery, parameters, classType));
        }
        private void createIncompleteTable(Serializable objeto)
        {
            if (existsTable(objeto.getTableName()))
            {
                return;
            }

            string createQuery = "create table " + objeto.getTableName() + "(";

            foreach (var item in listProperties(objeto))
            {
                if (!isSerializableProperty(item, objeto))
                {
                    String dataType = getDataTypeName(getPropertyType(item, objeto));

                    if (dataType != "" && objeto.getMapFromKey(item) != "")
                    {
                        createQuery += objeto.getMapFromKey(item) + " " + dataType;

                        if (objeto.getIdPropertyName() == item)
                        {
                            createQuery += " not null primary key";

                            if (objeto.getPrimaryKeyType() == PrimaryKeyType.SURROGATE)
                            {
                                createQuery += " identity(1,1)";
                            }
                        }

                        createQuery += ",";
                    }
                }
            }

            createQuery  = createQuery.Remove(createQuery.Length - 1);
            createQuery += ")";

            DataBase.Instance.ejecutarConsulta(createQuery);
        }
        private void completeOneToManyProperty(Serializable incompleteObject, string propertyName)
        {
            Type containingTypeOfProperty = incompleteObject.getOneToManyPropertyType(propertyName);

            Serializable containingTypeOfPropertyInstance = (Serializable)Activator.CreateInstance(containingTypeOfProperty);

            string intermediateTable = incompleteObject.getOneToManyTable(propertyName);
            string currentForeignKey = incompleteObject.getOneToManyFk(propertyName);
            string currentPrimaryKey = incompleteObject.getOneToManyPk(propertyName);

            object currentIdValue = incompleteObject.getPkValue();

            string expected = "@" + currentPrimaryKey;
            List <SqlParameter> sqlParameters = new List <SqlParameter>();

            DataBase.Instance.agregarParametro(sqlParameters, expected, currentIdValue);

            string query          = "select * from " + intermediateTable + " ";
            string conditionQuery = "where " + currentPrimaryKey + "=" + expected;

            if (containingTypeOfPropertyInstance.getTableName() != intermediateTable)
            {
                query += "inner join " + containingTypeOfPropertyInstance.getTableName() +
                         " on(" + intermediateTable + "." + currentForeignKey + "=" +
                         containingTypeOfPropertyInstance.getTableName() + "." +
                         containingTypeOfPropertyInstance.
                         getMapFromKey(containingTypeOfPropertyInstance.getIdPropertyName()) + ") ";
            }

            query += conditionQuery;

            Type listType = incompleteObject.getPropertyType(propertyName);

            object dummyList = Activator.CreateInstance(listType);

            //Asigno una lista vacia a la propiedad
            incompleteObject.GetType().GetProperty(propertyName).
            SetValue(incompleteObject, dummyList);

            foreach (var item in executeQuery(query, sqlParameters, containingTypeOfProperty))
            {
                List <object> parameters = new List <object> {
                    item
                };
                incompleteObject.GetType().GetProperty(propertyName).
                PropertyType.GetMethod("Add").
                Invoke(incompleteObject.getPropertyValue(propertyName), parameters.ToArray());
            }
        }
        private object unSerialize(Dictionary <string, object> dictionary, Type modelClassType)
        {
            Serializable objeto = (Serializable)Activator.CreateInstance(modelClassType);

            Dictionary <string, object> dictionaryAux = copyDictionary(dictionary);

            foreach (String dataName in dictionary.Keys)
            {
                String propertyName = objeto.getMapFromVal(dataName);
                String keyToRemove  = dataName;

                if (propertyName != "")
                {
                    Type propertyType = objeto.getPropertyType(propertyName);

                    bool isSerializable = typeof(Serializable).IsAssignableFrom(propertyType);

                    if (dictionary[dataName].ToString() != "")//Esto esta hardcodeado para que no setee cosas en null
                    {
                        if (isSerializable)
                        {
                            Serializable propertyInstance = (Serializable)Activator.CreateInstance(propertyType);
                            keyToRemove = propertyInstance.getMapFromKey(propertyInstance.getIdPropertyName());

                            object dataValue = dictionaryAux[dataName];
                            dictionaryAux.Remove(dataName);

                            if (!dictionaryAux.ContainsKey(keyToRemove))//parchado porque rompio en un test diciendo que ya se habia insertado la clave
                            {
                                dictionaryAux.Add(keyToRemove, dataValue);
                            }

                            objeto.GetType().GetProperty(propertyName).SetValue(objeto, unSerialize(dictionaryAux, propertyType));
                        }

                        else
                        {
                            object dataValue = getCastedValue(dictionary[dataName], objeto.getPropertyType(propertyName));
                            objeto.GetType().GetProperty(propertyName).SetValue(objeto, dataValue);
                        }
                        dictionaryAux.Remove(keyToRemove);
                    }
                }
            }

            return(objeto);
        }
        private void createOneToManyTables(Serializable objeto)
        {
            foreach (var item in objeto.getOneToManyPropertyNames())
            {
                string tableName = objeto.getOneToManyTable(item);

                if (!existsTable(tableName))
                {
                    createOneToManyTable(objeto, item);
                }
                else
                {
                    addOneToManyForeignKey(objeto.getMapFromKey(objeto.getIdPropertyName()),
                                           tableName, objeto.getTableName(),
                                           objeto.getOneToManyPk(item),
                                           objeto.getPropertyType(objeto.getIdPropertyName()));
                }
            }
        }
        private List <Dictionary <string, string> > getParsedQueryMethod(string methodName)
        {
            Serializable objeto = (Serializable)Activator.CreateInstance(getModelClassType());

            List <Dictionary <string, string> > columnsAndConnectors = new List <Dictionary <string, string> >();

            string unparsedQuery = methodName.Remove(0, 8);//methodName.Split(new string[] { "By" }, StringSplitOptions.None)[1];

            List <char> enumerableUnparsedQuery = unparsedQuery.ToList();

            int counter = 0;

            for (int i = 0; i < enumerableUnparsedQuery.Count; i++)
            {
                Dictionary <string, string> newDictionary = new Dictionary <string, string>();

                string column   = "";
                string property = "";

                if (i + 3 >= enumerableUnparsedQuery.Count)
                {
                    property = unparsedQuery.Substring(counter, unparsedQuery.Length - counter);//unparsedQuery;

                    column = property;
                    char[] dummyArray = column.ToCharArray();
                    dummyArray[0] = property[0].ToString().ToLower()[0];
                    column        = new string(dummyArray);
                    column        = objeto.getMapFromKey(column);

                    if (column == "")
                    {
                        column = objeto.getMapFromKey(property);
                    }

                    newDictionary.Add("column", column);
                    newDictionary.Add("connector", "");
                    columnsAndConnectors.Add(newDictionary);
                    break;
                }
                if (enumerableUnparsedQuery[i] == 'O' && enumerableUnparsedQuery[i + 1] == 'r')
                {
                    property = unparsedQuery.Substring(counter, i - counter);//unparsedQuery.Remove(i, unparsedQuery.Length - i);
                    counter += property.Length + 2;

                    column = property;
                    char[] dummyArray = column.ToCharArray();
                    dummyArray[0] = property[0].ToString().ToLower()[0];
                    column        = new string(dummyArray);
                    column        = objeto.getMapFromKey(column);

                    if (column == "")
                    {
                        column = objeto.getMapFromKey(property);
                    }

                    newDictionary.Add("column", column);
                    newDictionary.Add("connector", "or");
                    //unparsedQuery = unparsedQuery.Remove(0, i + 2);
                    columnsAndConnectors.Add(newDictionary);
                }
                if (enumerableUnparsedQuery[i] == 'A' && enumerableUnparsedQuery[i + 1] == 'n' && enumerableUnparsedQuery[i + 2] == 'd')
                {
                    property = unparsedQuery.Substring(counter, i - counter);//unparsedQuery.Remove(i, unparsedQuery.Length - i);
                    counter += property.Length + 3;

                    column = property;
                    char[] dummyArray = column.ToCharArray();
                    dummyArray[0] = property[0].ToString().ToLower()[0];
                    column        = new string(dummyArray);
                    column        = objeto.getMapFromKey(column);

                    if (column == "")
                    {
                        column = objeto.getMapFromKey(property);
                    }

                    newDictionary.Add("column", column);
                    newDictionary.Add("connector", "and");
                    //unparsedQuery = unparsedQuery.Remove(0, i + 3);
                    columnsAndConnectors.Add(newDictionary);
                }
            }

            return(columnsAndConnectors);
        }
        private void insert(Serializable objeto, String primaryKeyPropertyName, String tableName, bool cascade)
        {
            String insertQuery = "insert into " + tableName + "(";

            String valuesString = " values (";

            List <SqlParameter> parametros = new List <SqlParameter>();

            Dictionary <string, object> propertyValues = getPropertyValues(objeto);

            foreach (KeyValuePair <string, object> keyValuePair in propertyValues)
            {
                if (keyValuePair.Key != primaryKeyPropertyName || objeto.getPrimaryKeyType() == PrimaryKeyType.NATURAL)
                {
                    String dataName = objeto.getMapFromKey(keyValuePair.Key);

                    if (dataName != "")
                    {
                        insertQuery += dataName + ",";

                        valuesString += "@" + dataName + ",";

                        bool isSerializableProperty = typeof(Serializable).IsAssignableFrom(keyValuePair.Value.GetType());

                        Serializable serializableProperty = isSerializableProperty ? (Serializable)keyValuePair.Value : null;

                        if (cascade && isSerializableProperty)
                        {
                            insert(serializableProperty, serializableProperty.getIdPropertyName(), serializableProperty.getTableName(), true);
                        }

                        object parametro = isSerializableProperty ? serializableProperty.getPropertyValue(
                            serializableProperty.getIdPropertyName()) : keyValuePair.Value;

                        DataBase.Instance.agregarParametro(parametros, "@" + dataName, parametro);
                    }
                }
            }

            string primaryKeyName = objeto.getMapFromKey(objeto.getIdPropertyName());

            insertQuery  = insertQuery.Remove(insertQuery.Length - 1);
            valuesString = valuesString.Remove(valuesString.Length - 1);
            insertQuery += ") " + "output inserted." + primaryKeyName
                           + valuesString + ")";

            object insertResult = DataBase.Instance.ejecutarConsulta(
                insertQuery, parametros)[0][primaryKeyName];

            Type idType = objeto.getPropertyType(objeto.getIdPropertyName());

            object idValue = null;

            if (typeof(Serializable).IsAssignableFrom(idType))
            {
                idValue = objeto.getIdValue();
                Serializable serializableId = (Serializable)idValue;
                serializableId.GetType().GetProperty(serializableId.getIdPropertyName()).
                SetValue(serializableId,
                         getCastedValue(insertResult,
                                        serializableId.
                                        getPropertyType(serializableId.getIdPropertyName())));
            }
            else
            {
                idValue = getCastedValue(insertResult, idType);
            }

            objeto.GetType().GetProperty(objeto.getIdPropertyName()).SetValue(objeto, idValue);

            foreach (var item in objeto.getOneToManyPropertyNames())
            {
                insertOneToManyProperty(objeto, item, cascade);
            }
        }
        private void createForeignKeys(Serializable objeto)
        {
            int serializablePropertyCounter = listProperties(objeto).Count(property =>
                                                                           isSerializableProperty(property, objeto) && objeto.getMapFromKey(property) != "");

            if (serializablePropertyCounter == 0)
            {
                return;
            }

            bool existsFkEqualToPk = listProperties(objeto).Exists(prop =>
                                                                   objeto.getMapFromKey(prop) == objeto.getMapFromKey(objeto.getIdPropertyName()) &&
                                                                   typeof(Serializable).IsAssignableFrom(getPropertyType(prop, objeto)));

            //Este es el caso en el que la pk sea una fk y que solo haya 1 fk
            if (serializablePropertyCounter == 1 && existsFkEqualToPk)
            {
                Type propertyType = getPropertyType(listProperties(objeto).Find(prop =>
                                                                                isSerializableProperty(prop, objeto)), objeto);

                Serializable property = dictionaryObjectsAndTypes[propertyType];
                DataBase.Instance.ejecutarConsulta("alter table " + objeto.getTableName() +
                                                   " add foreign key(" + objeto.getMapFromKey(objeto.getIdPropertyName()) +
                                                   ") references " + property.getTableName() + "(" +
                                                   property.getMapFromKey(property.getIdPropertyName()) + ")");

                return;
            }

            string alterQuery = "alter table " + objeto.getTableName() + " add ";

            string foreignKeys = "";

            foreach (var item in listProperties(objeto))
            {
                Type propertyType = getPropertyType(item, objeto);

                if (isSerializableProperty(item, objeto) && objeto.getMapFromKey(item) != "")
                {
                    Serializable property       = dictionaryObjectsAndTypes[propertyType];
                    Type         idPropertyType = getPropertyType(property.getIdPropertyName(), property);

                    string primaryKeyProperty = property.getMapFromKey(property.getIdPropertyName());
                    string foreignKeyProperty = objeto.getMapFromKey(item);
                    string tableNameProperty  = property.getTableName();

                    if (objeto.getMapFromKey(item) != objeto.getMapFromKey(objeto.getIdPropertyName()))//Si es la pk, ya se inserto
                    {
                        alterQuery += foreignKeyProperty + " " + getDataTypeName(idPropertyType) + ",";
                    }

                    foreignKeys += "foreign key(" + foreignKeyProperty + ") references "
                                   + tableNameProperty + "(" + primaryKeyProperty + "),";
                }
            }

            foreignKeys = foreignKeys.Remove(foreignKeys.Length - 1);
            alterQuery += foreignKeys;

            DataBase.Instance.ejecutarConsulta(alterQuery);
        }