public function save(AbstractDbEntity $dbEntity)
    {
        if ($dbEntity->shouldBeDeletedFromDbOnSave()) {
            // Only delete if previously saved to db
            if ($dbEntity->getPrimaryDbValue()) {
                $this->delete($dbEntity);
            }

            return false;
        }

        if ($dbEntity->shouldInsertOnDbSave()) {
            // Note that database data always contains all properties,
            // with defaults for non set properties
            $dataToSave = $dbEntity->getDbData();
        } else {
            if ($dbEntity->hasModifiedDbProperties()) {
                $dataToSave = $dbEntity->getModifiedDbData();
            } else {
                // Return if no value has been modified and it's not an insert
                // (we always want to insert if no id exist, since some child objects might
                // depend on the this primary id being available)
                return false;
            }
        }

        // Check data
        $sqlData = [];
        foreach ($dataToSave as $propertyName => $value) {
            if (!empty($value) && is_scalar($value)
                && $dbEntity->getDbPropertyMaxLength($propertyName)
                && mb_strlen($value) > $dbEntity->getDbPropertyMaxLength($propertyName)
            ) {
                throw new \RuntimeException(
                    "Database field \"{$propertyName}\" exceeds field max length (value: \"{$value}\")"
                );
            } elseif (empty($value) && $dbEntity->getDbPropertyNonEmpty($propertyName)) {
                throw new \RuntimeException("Database field \"{$propertyName}\" is empty and required");
            } elseif (((is_scalar($value) && ((string) $value) === '') || (!is_scalar($value) && empty($value)))
                && $dbEntity->getDbPropertyRequired($propertyName)
            ) {
                throw new \RuntimeException("Database field \"{$propertyName}\" is required to be set");
            }

            // Set data keys db field format
            $fieldName = $dbEntity->getDbFieldName($propertyName);
            $sqlData[$fieldName] = $value;
        }


        // Insert new database row
        if ($dbEntity->shouldInsertOnDbSave()) {
            $this->db->insert(
                $dbEntity->getDbTableName(),
                $sqlData
            );

            // Update entity with auto increment value
            if (!is_array($dbEntity->getPrimaryDbPropertyKey())
                && !empty($lastInsertId = $this->db->getLastInsertId())
            ) {
                $dbEntity->setPrimaryDbValue($lastInsertId);
            } else {
                // For entities with for example string primary keys, we update primary value
                // with value/values from db data, indicating that the entity is now
                // in database/loaded.
                $dbEntity->updatePrimaryDbValueFromDbData();
            }
        // Update existing database row
        } else {
            $this->db->update(
                $dbEntity->getDbTableName(),
                $sqlData,
                $this->getPrimaryKeyWhereSql($dbEntity),
                $this->getPrimaryKeyWhereParameters($dbEntity)
            );
        }

        $dbEntity->clearModifiedDbProperties();
        $dbEntity->setForceDbInsertOnSave(false);

        return true;
    }