Инъекция зависимостей в методе семян Entity Framework?

Можно ли встраивать зависимости в класс конфигурации Entity Framework 6?

Например, например:

internal sealed class Configuration : DbMigrationsConfiguration<MyBaseContext>
{
    private readonly ILogger _logger;

    public Configuration(ILogger logger)
    {
        this._logger = logger;
        AutomaticMigrationsEnabled = true;
    }

    protected override void Seed(Home.DAL.Data.HomeBaseContext context)
    {
         //log something
    }
}

Или более общий подход заключается в том, чтобы получить возможность вводить код даже внутри миграций:

public partial class InitialMigration : DbMigration
{        
    private readonly ILogger _logger;

    public InitialMigration(ILogger logger)
    {            
         this._logger = logger;
    }

    public override void Up()
    {
        CreateTable(...);
    }

    public override void Down()
    {
        DropTable(...);
    }
}

Где инициализация DI происходит в Entity Framework 6 для определения этих привязок?

UPDATE

Я не спрашиваю о том, что я должен использовать. В настоящее время я использую Ninject, но это не может быть и речи, потому что, что бы я ни использовал, я должен был бы вставлять dependecies в конструктор миграции. Если вы пишете что-то вроде того, что я написал в примере выше, он просто выкинет вам исключение из "конструктора по умолчанию".

ILogger в приведенном выше примере - просто простой пример зависимости. Дела идут хуже, если у вас есть IGeneratorService, который будет генерировать некоторые данные, и вы хотите использовать эту службу для генерации данных для метода Seed.

Ответ 1

Entity Framework 6 предполагает, что вы используете .NET Framework 4.6 или ниже, и нет встроенных возможностей встраивания зависимостей для .NET 4.6 или ниже, поэтому вам необходимо использовать сторонние контейнеры DI, такие как StructureMap, Ninject и т.д. Эти контейнеры DI дают вам 3 способа получить инъекцию зависимостей: через конструктор, сеттер или интерфейс.

Я не совсем уверен, возможно ли использовать конструкторскую инъекцию для встраивания зависимостей в класс Configuration или InitialMigration, но я сомневаюсь. Даже если это возможно, вы не сможете ввести ILogger способ, которым вы описываете в своем вопросе: this._logger = logger, потому что ILogger инициализируется с использованием метода ILoggerFactory Create().

Таким образом, я не думаю, что его можно вставлять зависимости в классы Configuration или InitialMigration, используя в целом конструктор.

Если вы хотите использовать ILogger в своих классах, следующие фрагменты кода должны работать:

internal sealed class Configuration : DbMigrationsConfiguration<MyBaseContext>
{
    private readonly ILogger _logger;

    public Configuration(ILoggerFactory loggerFactory)
    {
        this._logger = loggerFactory.Create("ConfigurationLogger");
        AutomaticMigrationsEnabled = true;
    }

    protected override void Seed(Home.DAL.Data.HomeBaseContext context)
    {
         //log something
         _logger.WriteInformation("Seeding data.");
    }
}

public partial class InitialMigration : DbMigration
{        
    private readonly ILogger _logger;

    public InitialMigration(ILoggerFactory loggerFactory)
    {            
         this._logger = loggerFactory.Create("InitialMigrationLogger");
    }

    public override void Up()
    {
        _logger.WriteInformation("Create table.");
        CreateTable(...);
    }

    public override void Down()
    {
        _logger.WriteInformation("Drop table.");
        DropTable(...);
    }
}

Ответ 2

Я так не думаю. Конечно, не при использовании базы данных обновлений из командной строки. Помните, что ваш контейнер DI зарегистрирован во время выполнения. Не было бы никаких услуг, которые можно было бы вводить в любом месте. В дополнение к этому EF ищет файл конфигурации с конструктором без параметров. Вы можете быстро проверить это на примере с вашего вопроса. В сборке "Your.Assembly" вы найдете "Тип конфигурации миграции".

Если вы специально хотите выполнить какое-либо действие со службой в вашем методе семени, я бы предложил заглянуть в runtime api, на который был дан ответ здесь.

Я использую консольное приложение в своих проектах, чтобы отправлять команды в качестве части моего конвейера сборки при развертывании. Вы можете легко использовать этот подход в своей фактической базе кода.

private void RunMigrations()
    {
        Console.WriteLine("Starting migrations...");
        var configuration = new Configuration
        {
            TargetDatabase = new DbConnectionInfo(_connectionString, "System.Data.SqlClient")
        };
        var dbMigrator = new DbMigrator(configuration);
        dbMigrator.Update();
        Console.WriteLine("Migrations completed");

        //add your service here and do whatever you want.
    }

    private void Seed()
    {
        using (var MyContext = new MyContext(_connectionString))
        {
            Console.WriteLine("Seeding test data into database");
            //this is a custom seed method
            Initialize.Seed(_connectionString);
            Console.WriteLine("Seeding test data is complete");

            //add your service here and do whatever you want.
        }
    }