protected function cacheDatabaseFields($class)
    {
        // Skip if already cached
        if (isset($this->databaseFields[$class]) && isset($this->compositeFields[$class])) {
            return;
        }
        $compositeFields = array();
        $dbFields = array();

        // Ensure fixed fields appear at the start
        $fixedFields = DataObject::config()->uninherited('fixed_fields');
        if (get_parent_class($class) === DataObject::class) {
            // Merge fixed with ClassName spec and custom db fields
            $dbFields = $fixedFields;
        } else {
            $dbFields['ID'] = $fixedFields['ID'];
        }

        // Check each DB value as either a field or composite field
        $db = Config::inst()->get($class, 'db', Config::UNINHERITED) ?: array();
        foreach ($db as $fieldName => $fieldSpec) {
            $fieldClass = strtok($fieldSpec, '(');
            if (singleton($fieldClass) instanceof DBComposite) {
                $compositeFields[$fieldName] = $fieldSpec;
            } else {
                $dbFields[$fieldName] = $fieldSpec;
            }
        }

        // Add in all has_ones
        $hasOne = Config::inst()->get($class, 'has_one', Config::UNINHERITED) ?: array();
        foreach ($hasOne as $fieldName => $hasOneClass) {
            if ($hasOneClass === DataObject::class) {
                $compositeFields[$fieldName] = 'PolymorphicForeignKey';
            } else {
                $dbFields["{$fieldName}ID"] = 'ForeignKey';
            }
        }

        // Merge composite fields into DB
        foreach ($compositeFields as $fieldName => $fieldSpec) {
            $fieldObj = Injector::inst()->create($fieldSpec, $fieldName);
            $fieldObj->setTable($class);
            $nestedFields = $fieldObj->compositeDatabaseFields();
            foreach ($nestedFields as $nestedName => $nestedSpec) {
                $dbFields["{$fieldName}{$nestedName}"] = $nestedSpec;
            }
        }

        // Prevent field-less tables with only 'ID'
        if (count($dbFields) < 2) {
            $dbFields = [];
        }

        // Return cached results
        $this->databaseFields[$class] = $dbFields;
        $this->compositeFields[$class] = $compositeFields;
    }