public function save($deep = true)
    {
        // run before save
        $this->beforeSave();

        if (static::isVersioned()) {
            $this->beforeVersionedSave();
        }

        // set created
        if (static::fieldExists('Created') && (!$this->Created || ($this->Created == 'CURRENT_TIMESTAMP'))) {
            $this->Created = time();
        }

        // validate
        if (!$this->validate($deep)) {
            throw new Exception('Cannot save invalid record');
        }

        $this->clearCaches();

        if ($this->isDirty) {
            // prepare record values
            $recordValues = $this->_prepareRecordValues();

            // transform record to set array
            $set = static::_mapValuesToSet($recordValues);

            // create new or update existing
            if ($this->_isPhantom) {
                DB::nonQuery(
                    'INSERT INTO `%s` SET %s',
                    [
                        static::$tableName,
                        join(',', $set),
                    ],
                    [static::class,'handleError']
                );

                $this->_record[static::$primaryKey ? static::$primaryKey : 'ID'] = DB::insertID();
                $this->_isPhantom = false;
                $this->_isNew = true;
            } elseif (count($set)) {
                DB::nonQuery(
                    'UPDATE `%s` SET %s WHERE `%s` = %u',
                    [
                        static::$tableName,
                        join(',', $set),
                        static::_cn(static::$primaryKey ? static::$primaryKey : 'ID'),
                        $this->getPrimaryKeyValue(),
                    ],
                    [static::class,'handleError']
                );

                $this->_isUpdated = true;
            }

            // update state
            $this->_isDirty = false;

            if (static::isVersioned()) {
                $this->afterVersionedSave();
            }
        }
        $this->afterSave();
    }