public bool Delete(bool fireBeforeDeleteDataEvent = true, bool fireAfterDeleteDataEvent = true, TransactionObject transaction = null)
        {
#if !PCL
            var _table    = TableDefinition.GetTableDefinition(typeof(T));
            var _function = _table.DefaultDataFunction;

            if (fireBeforeDeleteDataEvent)
            {
                this.OnBeforeDeleteData(new NotifyRecordChangesEventArgs(0, SqlStatementsTypes.Delete, transaction));
            }

            var _ret = _function.Delete(this, transaction);

            ThrowException(_ret);

            if (fireAfterDeleteDataEvent)
            {
                this.OnAfterDeleteData(new NotifyRecordChangesEventArgs(_ret.RecordsAffected, _ret.ChangeType, transaction));
            }

            return(_ret.RecordsAffected > 0);
#else
            return(true);
#endif
        }
        public int Update(bool fireOnAfterSaveData = true, bool validateData = false, TransactionObject transaction = null)
        {
#if !PCL
            var _table    = TableDefinition.GetTableDefinition(typeof(T));
            var _function = _table.DefaultDataFunction;

            if (validateData)
            {
                if (!this.OnValidateData())
                {
                    return(0);
                }
            }

            var _ret = _function.Update(this, transaction);

            ThrowException(_ret);

            if (fireOnAfterSaveData)
            {
                this.OnAfterSaveData(new NotifyRecordChangesEventArgs(_ret.RecordsAffected, _ret.ChangeType, transaction));
            }

            return(_ret.RecordsAffected);
#else
            return(0);
#endif
        }
        public bool AlterTable <TDatabaseObject>() where TDatabaseObject : IDatabaseObject
        {
#if !PCL
            try
            {
                var _table  = TableDefinition.GetTableDefinition(typeof(TDatabaseObject));
                var _backup = BackupData <TDatabaseObject>();

                DropTable <TDatabaseObject>();

                using (var _conn = _table.DefaultDataFunction.Connection)
                {
                    _conn.Execute(_table.GetScriptCreateTable());
                }

                foreach (var _bkp in _backup)
                {
                    (_bkp as IDatabaseObject).SaveChanges();
                }

                return(true);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message, ex);
            }
#else
            return(false);
#endif
        }
        public static bool CheckDdlScript <TDatabaseObject>(string path) where TDatabaseObject : IDatabaseObject
        {
#if !PCL
            var _file   = Path.Combine(path, DatabaseObject <TDatabaseObject> .ObjectName + ".sql");
            var _oldDdl = "";

#if WINDOWS_PHONE_APP
            _oldDdl = Task.Run(async() => await GetScriptAsync(_file)).Result;

            if (_oldDdl == "")
            {
                return(false);
            }
#else
            if (!File.Exists(_file))
            {
                return(false);
            }

            _oldDdl = File.ReadAllText(_file);
#endif
            var _curDdl = TableDefinition.GetTableDefinition(typeof(TDatabaseObject)).GetScriptCreateTable();
            var _ret    = _oldDdl.Equals(_curDdl);
            return(_ret);
#else
            return(false);
#endif
        }
        private static DboCommand GetDboCommand(Expression <Func <T, bool> > predicate = null, bool useFieldNames = true, SqlStatementsTypes sqlType = SqlStatementsTypes.Select, object obj = null)
        {
            var _tableDef     = TableDefinition.GetTableDefinition(typeof(T));
            var _selectFields = _tableDef.GetStatementSelect(sqlType == SqlStatementsTypes.SelectReload);

            DboCommand _sqlCommand = null;

            switch (sqlType)
            {
            case SqlStatementsTypes.Select:
                _sqlCommand = GetCommandSelect(_selectFields, predicate, _tableDef);
                break;

            case SqlStatementsTypes.DeleteAll:
                _sqlCommand = GetCommandDelete(predicate);
                break;

            case SqlStatementsTypes.SelectReload:
                _sqlCommand = GetCommandSelectReloadMe(_selectFields, obj);
                break;

            default:
                throw new NotImplementedException();
            }

            return(_sqlCommand);
        }
        public int Insert(bool ignoreAutoIncrementField = true, bool fireOnAfterSaveData = true, bool validateData = false, TransactionObject transaction = null)
        {
#if !PCL
            var _table    = TableDefinition.GetTableDefinition(typeof(T));
            var _function = _table.DefaultDataFunction;

            if (validateData)
            {
                if (!this.OnValidateData())
                {
                    return(0);
                }
            }

            var _ret = _function.Insert(this, ignoreAutoIncrementField, transaction);

            ThrowException(_ret);

            if (_ret.ReturnStatus == CrudStatus.Ok && _ret.ChangeType == SqlStatementsTypes.Insert)
            {
                this.SetSelfColumnsIds(_ret.ReturnData);
            }

            if (fireOnAfterSaveData)
            {
                this.OnAfterSaveData(new NotifyRecordChangesEventArgs(_ret.RecordsAffected, _ret.ChangeType, transaction));
            }

            return(_ret.RecordsAffected);
#else
            return(-1);
#endif
        }
        private static IEnumerable <FieldDefAttribute> GetObjectFields()
        {
#if !PCL
            return(TableDefinition.GetTableDefinition(typeof(T)).Fields.Select(f => f.Value));
#else
            return(new List <FieldDefAttribute>());
#endif
        }
        private static IEnumerable <FieldDefAttribute> GetPrimaryKeyFields <TDatabaseObject>()// where TDatabaseObject : IDatabaseObject
        {
#if !PCL
            return(TableDefinition.GetTableDefinition(typeof(TDatabaseObject)).Fields.Where(f => f.Value.IsPrimaryKey).Select(f => f.Value));
#else
            return(new List <FieldDefAttribute>());
#endif
        }
        public T ReloadMe()
        {
#if !PCL
            var _command = GetDboCommand(null, true, SqlStatementsTypes.SelectReload, this);
            var _ret     = TableDefinition.GetTableDefinition(typeof(T)).DefaultDataFunction.ReloadMe <T>(_command);
            return(_ret);
#else
            return(default(T));
#endif
        }
        public CrudReturn Insert <TDatabaseObject>(TDatabaseObject objectToInsert, bool ignoreAutoIncrementField = true, TransactionObject transaction = null) where TDatabaseObject : IDatabaseObject
        {
            var _table = TableDefinition.GetTableDefinition(typeof(TDatabaseObject));

            var _ret = new CrudReturn
            {
                ReturnStatus    = CrudStatus.Ok,
                RecordsAffected = -1,
                ChangeType      = SqlStatementsTypes.Insert,
                ReturnMessage   = "Dados atualizados com sucesso!"
            };

            var _transaction = transaction ?? new TransactionObject(true);

            try
            {
                if (_transaction.Connection == null)
                {
                    _transaction.SetConnection(_table.DefaultDataFunction.Connection);
                }

                var _sql          = "";
                var _data         = objectToInsert.ToDictionary();
                var _backEndField = _table.Fields.Select(f => f.Value).FirstOrDefault(f => f.AutomaticValue != AutomaticValue.None);

                if (_backEndField != null)
                {
                    _sql = _table.GetSqlInsert(ignoreAutoIncrementField);
                    int _lastId = this.DoInsert(_table, _transaction.Connection, _sql, _data);
                    objectToInsert.SetObjectFieldValue(_backEndField.Name, _lastId);
                    _ret.RecordsAffected = 1;
                }
                else
                {
                    objectToInsert.SetIdFields();
                    _sql = _table.GetSqlInsert(ignoreAutoIncrementField);
                    _ret.RecordsAffected = _transaction.Connection.Execute(_sql, _data);
                }

                _ret.ReturnData = objectToInsert;

                if (_transaction.AutoCommit)
                {
                    _transaction.Commit();
                    _transaction.Dispose();
                }
            }
            catch (Exception ex)
            {
                _ret.ReturnMessage = string.Format("{0}\r\n{1}", ex.Message, ex.StackTrace);
                _ret.ReturnStatus  = CrudStatus.Fail;
            }

            return(_ret);
        }
        public bool Exists()
        {
#if !PCL
            var _table = TableDefinition.GetTableDefinition(typeof(T));
            var _sql   = _table.GetSqlSelectForCheck();

            return(_table.DefaultDataFunction.Exists(_sql, this));
#else
            throw new Exception("CĂłdigo executado via PCL!");
#endif
        }
        public static IEnumerable <T> Query(Expression <Func <T, bool> > predicate = null)
        {
#if !PCL
            const bool useFieldNames = true;
            var        _command      = GetDboCommand(predicate, useFieldNames);
            var        _ret          = TableDefinition.GetTableDefinition(typeof(T)).DefaultDataFunction.Query <T>(_command, useFieldNames);
            return(_ret);
#else
            throw new Exception("CĂłdigo executado via PCL!");
#endif
        }
        public static int DeleteAll(Expression <Func <T, bool> > predicate = null, TransactionObject transaction = null)
        {
#if !PCL
            var _table   = TableDefinition.GetTableDefinition(typeof(T));
            var _command = GetDboCommand(predicate, false, SqlStatementsTypes.DeleteAll);
            var _ret     = _table.DefaultDataFunction.DeleteAll <T>(_command, transaction);

            return(_ret.RecordsAffected);
#else
            return(-1);
#endif
        }
        public static bool Exists(Expression <Func <T, bool> > predicate)
        {
#if !PCL
            var _table      = TableDefinition.GetTableDefinition(typeof(T));
            var _sql        = "select count(0) as tt from " + ObjectName;
            var _sqlCommand = GetCommandSelect(_sql, predicate);

            return(_table.DefaultDataFunction.Exists(_sqlCommand));
#else
            throw new Exception("CĂłdigo executado via PCL!");
#endif
        }
        public static void Truncate(bool useDropAndCreate = false)
        {
#if !PCL
            var _table    = TableDefinition.GetTableDefinition(typeof(T));
            var _function = _table.DefaultDataFunction;

            var _ret = _function.ExecuteStatement(_table.GetScriptDropTable());
            ThrowException(_ret);

            _ret = _function.ExecuteStatement(_table.GetScriptCreateTable());
            ThrowException(_ret);
#endif
        }
        public static IEnumerable <T> Query(string sqlStatement, object dynamicParameters = null)
        {
#if !PCL
            var    _function   = TableDefinition.GetTableDefinition(typeof(T)).DefaultDataFunction;
            string _parameters = null;
            if (dynamicParameters != null)
            {
                _parameters = JsonConvert.SerializeObject(dynamicParameters, GetJsonSerializerSettings());
            }
            var _ret = _function.Query <T>(sqlStatement, _parameters);
            //var _ret = TableDefinition.GetTableDefinition(typeof(T)).DefaultDataFunction.Query<T>(sqlStatement, dynamicParameters);
            return(_ret);
#else
            throw new Exception("CĂłdigo executado via PCL!");
#endif
        }
        public static void SaveDdlScript <TDatabaseObject>(string path) where TDatabaseObject : IDatabaseObject
        {
            var _ddl  = TableDefinition.GetTableDefinition(typeof(TDatabaseObject)).GetScriptCreateTable();
            var _file = Path.Combine(path, DatabaseObject <TDatabaseObject> .ObjectName + ".sql");

#if !PCL
#if WINDOWS_PHONE_APP
            var _result = Task.Run(async() =>
            {
                var _storage = PCLStorage.FileSystem.Current.RoamingStorage;

                if (await _storage.CheckExistsAsync(path) != ExistenceCheckResult.FolderExists)
                {
                    await _storage.CreateFolderAsync(path, CreationCollisionOption.FailIfExists);
                }


                if (await _storage.CheckExistsAsync(_file) == ExistenceCheckResult.FileExists)
                {
                    var _delete = await _storage.GetFileAsync(_file);
                    await _delete.DeleteAsync();
                }

                var _newfile = await _storage.CreateFileAsync(_file, CreationCollisionOption.ReplaceExisting);

                await _newfile.WriteAllTextAsync(_ddl);

                return(true);
            }).Result;

            var _a = _result;
#else
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            if (File.Exists(_file))
            {
                File.Delete(_file);
            }

            File.WriteAllText(_file, _ddl);
#endif
#endif
        }
        private void DropTable <TDatabaseObject>()
        {
#if !PCL
            var _table = TableDefinition.GetTableDefinition(typeof(TDatabaseObject));

            try
            {
                using (var _conn = _table.DefaultDataFunction.Connection)
                {
                    _conn.Execute(_table.GetScriptDropTable());
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message, ex);
            }
#endif
        }
        private Func <bool> GetValidateDataFunction()
        {
#if !PCL
            return(m_ValidateDataFunction ?? (m_ValidateDataFunction = (() =>
            {
                var _table = TableDefinition.GetTableDefinition(typeof(T));
                var _rules = _table.Rules.Select(r => r.Value);
                var _validatedFields = new List <ValidatedField>();

                foreach (var _rule in _rules)
                {
                    if (!_rule.IsForValidate)
                    {
                        continue;
                    }
#if WINDOWS_PHONE_APP
                    var _prop = _table.BaseType.GetRuntimeProperties().FirstOrDefault(f => f.Name == _rule.Name);
#else
                    var _prop = _table.BaseType.GetProperties(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(f => f.Name == _rule.Name);
#endif
                    if (!_rule.Validate(_prop.GetValue(this)))
                    {
                        _validatedFields.Add(new ValidatedField()
                        {
                            FieldMessage = _rule.ValidationText, FieldName = _rule.Name
                        });
                    }
                }

                if (_validatedFields.Count > 0)
                {
                    this.RaiseErrorOnValidateData(new ErrorOnValidateDataEventArgs(_validatedFields.ToArray()));

                    return false;
                }

                return true;
            })));
#else
            return(new Func <bool>(() => false));
#endif
        }
        private void SetSelfColumnsIds(object value)
        {
#if !PCL
            var _table  = TableDefinition.GetTableDefinition(typeof(T));
            var _fields = _table.Fields.Select(f => f.Value).Where(f => f.AutomaticValue != AutomaticValue.None);

            foreach (var _field in _fields)
            {
#if WINDOWS_PHONE_APP
                var _prop = value.GetType().GetRuntimeProperties().FirstOrDefault(f => f.Name == _field.Name);
#else
                var _prop = value.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(f => f.Name == _field.Name);
#endif
                if (_prop != null)
                {
                    this.SetObjectFieldValue(_field.Name, _prop.GetValue(value));
                }
            }
#endif
        }
        public CrudReturn Update <TDatabaseObject>(TDatabaseObject objectToUpdate, TransactionObject transaction = null) where TDatabaseObject : IDatabaseObject
        {
            var _table = TableDefinition.GetTableDefinition(typeof(TDatabaseObject));
            var _ret   = new CrudReturn
            {
                ReturnStatus    = CrudStatus.Ok,
                RecordsAffected = -1,
                ChangeType      = SqlStatementsTypes.Update,
                ReturnMessage   = "Dados atualizados com sucesso!"
            };

            var _transaction = transaction ?? new TransactionObject(true);

            try
            {
                if (_transaction.Connection == null)
                {
                    _transaction.SetConnection(_table.DefaultDataFunction.Connection);
                }

                var _sql  = "";
                var _data = objectToUpdate.ToDictionary();

                _sql = _table.GetSqlUpdate();
                _ret.RecordsAffected = _transaction.Connection.Execute(_sql, _data);
                _ret.ReturnData      = objectToUpdate;

                if (_transaction.AutoCommit)
                {
                    _transaction.Commit();
                    _transaction.Dispose();
                }
            }
            catch (Exception ex)
            {
                _ret.ReturnMessage = string.Format("{0}\r\n{1}", ex.Message, ex.StackTrace);
                _ret.ReturnStatus  = CrudStatus.Fail;
            }

            return(_ret);
        }
        protected override IList <Newtonsoft.Json.Serialization.JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            var _isAnonymous = type.Name.ToLower().Contains("anonymoustype");

            var _properties = base.CreateProperties(type, memberSerialization);

            if (_isAnonymous)
            {
                return(_properties);
            }

            foreach (var _p in _properties)
            {
                var _att = _p.AttributeProvider.GetAttributes(false).FirstOrDefault(p => p.GetType() == typeof(JoinFieldAttribute));

                if (_att == null)
                {
                    _p.Ignored = true;
                }
                else
                {
                    if (!(_att as JoinFieldAttribute).SerializeField)
                    {
                        _p.Ignored = true;
                    }
                }
            }

            var _fields = TableDefinition.GetTableDefinition(type).Fields.Select(f => f.Value);

            foreach (var _field in _fields.Where(f => !m_NamesToRemove.Contains(f.Name)))
            {
                var _p = _properties.FirstOrDefault(p => p.PropertyName == _field.Name);
                if (_p != null)
                {
                    _p.Ignored = false;
                }
            }
            return(_properties);
        }
        private static DboCommand GetCommandSelect(string selectionList, Expression predicate, TableDefinition tabledef = null)
        {
            var _cmdText = selectionList;

            var _where         = predicate;
            var _nameAndValues = new Dictionary <string, object>();

            CompileResult _w = null;

            if (_where != null)
            {
                _w = CompileResult.CompileExpr(_where, _nameAndValues, TableDefinition.GetTableDefinition(typeof(T)).DefaultDataFunction.PrefixParameter, ObjectName);
            }

            if (_w != null)
            {
                if (tabledef != null)
                {
                    _cmdText += "\r\nwhere " + tabledef.ReplaceTableAlias(_w.CommandText, tabledef);
                }
                else
                {
                    _cmdText += "\r\nwhere " + _w.CommandText;
                }
            }

            // caso os join tenham algum filtro, inserimos ele neste momento
            var _joinDefs = TableDefinition.GetTableDefinition(typeof(T)).JoinFields.Select(j => j.Value);

            foreach (var _joinDef in _joinDefs)
            {
                foreach (var _parameter in _joinDef.GetFilterParameters())
                {
                    _nameAndValues.Add(_parameter.Key, _parameter.Value);
                }
            }

            return(new DboCommand(ObjectName, _cmdText, _nameAndValues));
        }
        /// <summary>
        /// Save current changes on object
        /// </summary>
        /// <param name="ignoreAutoIncrementAttribute">if true, doesn't include autoincrement or backend calculated fields on insert statement. Defaults to true</param>
        /// <param name="fireEvent">if true, fire the AfterSaveData event. Defaults to true</param>
        /// <param name="doNotUpdateWhenExists">if true, doesn't fire the update statement when a register already exists in the database. Defaults to false</param>
        /// <param name="validateData"></param>
        /// <returns>true if object is saved on database, otherwise false</returns>
        public bool SaveChanges(bool ignoreAutoIncrementAttribute = true, FireEvent fireEvent = FireEvent.OnBeforeAndAfter, bool doNotUpdateWhenExists = false, bool validateData = false, TransactionObject transaction = null)
        {
#if !PCL
            var _table    = TableDefinition.GetTableDefinition(typeof(T));
            var _function = _table.DefaultDataFunction;

            if (validateData)
            {
                if (!this.OnValidateData())
                {
                    return(false);
                }
            }

            if (fireEvent == FireEvent.OnBeforeAndAfter || fireEvent == FireEvent.OnBeforeSave)
            {
                this.OnBeforeSaveData(new NotifyRecordChangesEventArgs(0, SqlStatementsTypes.UnknownStatement, transaction));
            }

            var _ret = _function.SaveChanges(this, ignoreAutoIncrementAttribute, doNotUpdateWhenExists, transaction);

            ThrowException(_ret);

            if (_ret.ReturnStatus == CrudStatus.Ok && _ret.ChangeType == SqlStatementsTypes.Insert)
            {
                this.SetSelfColumnsIds(_ret.ReturnData);
            }

            if (fireEvent == FireEvent.OnBeforeAndAfter || fireEvent == FireEvent.OnAfterSave)
            {
                this.OnAfterSaveData(new NotifyRecordChangesEventArgs(_ret.RecordsAffected, _ret.ChangeType, transaction));
            }

            return(_ret.ReturnStatus == CrudStatus.Ok);
#else
            return(false);
#endif
        }
        private static Dictionary <string, object> ToDictionary(object value)
        {
            var _type = value.GetType();
            var _ret  = new Dictionary <string, object>();

            if (_type.Name.ToLower().Contains("anonymoustype"))
            {
                var _data = DatabaseObject <object> .ToJson(value);

                _ret = JsonConvert.DeserializeObject <Dictionary <string, object> >(_data, GetJsonSerializerSettings());
            }
            else
            {
                var _fields = TableDefinition.GetTableDefinition(_type).Fields.Select(f => f.Value);

                foreach (var _field in _fields)
                {
                    _ret.Add(_field.Name, _field.GetValue(value));
                }
            }

            return(_ret);
        }
        public CrudReturn DeleteAll <TDatabaseObject>(DboCommand command, TransactionObject transaction = null)
        {
            var _table = TableDefinition.GetTableDefinition(typeof(TDatabaseObject));
            var _ret   = new CrudReturn
            {
                ReturnStatus    = CrudStatus.Ok,
                RecordsAffected = -1,
                ChangeType      = SqlStatementsTypes.DeleteAll,
                ReturnMessage   = "Dados excluĂ­dos com sucesso!"
            };

            var _transaction = transaction ?? new TransactionObject(true);

            try
            {
                if (_transaction.Connection == null)
                {
                    _transaction.SetConnection(_table.DefaultDataFunction.Connection);
                }

                _ret.RecordsAffected = _transaction.Connection.Execute(command.GetCommandDefinition());

                if (_transaction.AutoCommit)
                {
                    _transaction.Commit();
                    _transaction.Dispose();
                }
            }
            catch (Exception ex)
            {
                _ret.ReturnMessage = string.Format("{0}\r\n{1}", ex.Message, ex.StackTrace);
                _ret.ReturnStatus  = CrudStatus.Fail;
            }

            return(_ret);
        }
        private static DboCommand GetCommandDelete(Expression predicate)
        {
            var _cmdText = "delete from " + ObjectName + " ";

            var _where          = predicate;
            var _namesAndValues = new Dictionary <string, object>();
            //var _argNames = new List<string>();
            //var _argValues = new List<object>();

            CompileResult _w = null;

            if (_where != null)
            {
                _w = CompileResult.CompileExpr(_where, /*_argNames, _argValues,*/ _namesAndValues, TableDefinition.GetTableDefinition(typeof(T)).DefaultDataFunction.PrefixParameter, ObjectName);
            }

            if (_w != null)
            {
                _cmdText += " where " + _w.CommandText;
            }

            return(new DboCommand(ObjectName, _cmdText, /*_argNames.ToArray(), _argValues.ToArray()*/ _namesAndValues));
        }
        private static DboCommand GetCommandSelect(string selectionList, Expression predicate, TableDefinition tabledef = null)
        {
            var _cmdText = selectionList;

            var _where         = predicate;
            var _nameAndValues = new Dictionary <string, object>();
            //var _argNames = new List<string>();
            //var _argValues = new List<object>();

            CompileResult _w = null;

            if (_where != null)
            {
                _w = CompileResult.CompileExpr(_where, /*_argNames, _argValues,*/ _nameAndValues, TableDefinition.GetTableDefinition(typeof(T)).DefaultDataFunction.PrefixParameter, ObjectName);
            }

            if (_w != null)
            {
                if (tabledef != null)
                {
                    _cmdText += "\r\nwhere " + tabledef.ReplaceTableAlias(_w.CommandText, tabledef);
                }
                else
                {
                    _cmdText += "\r\nwhere " + _w.CommandText;
                }
            }

            return(new DboCommand(ObjectName, _cmdText, /*_argNames.ToArray(), _argValues.ToArray()*/ _nameAndValues));
        }
        public string GetScriptDelete()
        {
            var _data = this.ToDictionary();

            return(TableDefinition.GetTableDefinition(typeof(T)).GetScriptDelete(_data));
        }
 string IDatabaseObject.GetDropTableScript()
 {
     return(TableDefinition.GetTableDefinition(typeof(T)).GetScriptDropTable());
 }