Question: How can we assign a theme in Magento 2.1 to a store using setup scripts?

Thank you

Answer: 
On Magento 2.1 and later (2.2 and 2.3 coming out) it is recommended to use service contract so I tried doing this without calling method in the model directly.

Unfortunately at this point there is no straight forward way in the core Magento\_Theme module service contract so we still have to make do with using some factory class.

First we need to inject the following classes to the setup script contructor:

```
use Magento\Theme\Api\DesignConfigRepositoryInterface;
use Magento\Theme\Model\Data\Design\ConfigFactory;
use Magento\Theme\Model\ResourceModel\Theme\CollectionFactory;

public function __construct(
        DesignConfigRepositoryInterface $designConfigRepository,
        CollectionFactory $themeCollectionFactory,
        ConfigFactory $themeConfigFactory) {...}

```

Next we will try to load the theme ID from it's path. Then we create a Design Config object by using factory class (hopefully Magento core will provide a service contract to do this in the future). Finally we use the ConfigRepository to save the value.

In this example my theme is for the frontend area, and has path MyVendorName/MyThemeName. 

```
if (version_compare($context->getVersion(), '1.0.0', '<')) {
    $themeCollection = $this->themeCollectionFactory->create();
    $theme = $themeCollection->getThemeByFullPath('frontend/MyVendorName/MyThemeName');
    $themeId = $theme->getId();

    $designConfigData = $this->themeConfigFactory->create('default', 0, ['theme_theme_id' => $themeId]);

    $this->designConfigRepository->save($designConfigData);
}

```

Notes: the designConfigRepository should take care of reindexing the grid.

Using this approach you can also change other theme configuration, for example:

```
$designConfigData = $this->themeConfigFactory->create('default', 0, [
'theme_theme_id' => $themeId,
'head_default_title' => 'My Default Title',
'head_demonotice' => 1 // Display demo store notice
]);

```

Obviously you can replace 'default' and '0' with relevant store scope. Hope this helps.
Above solutions work but have one shortcoming.
They assume that magento has already registered the theme, before setup script execution.
This is not always the case. If you revert entries in `setup_module` table, you discover that error is "magically fixed".

To avoid it, make sure that themes are registered before setup script execution.
One way to do it is 

```
\Magento\Theme\Model\Theme\Registration::register()

```