Как настроить контекст подключения EF Core для разделения зависимостей пакетов? - PullRequest
0 голосов
/ 12 сентября 2018

Я создал библиотеку для работы с постоянством, используя Entity Framework Core. Он используется веб-API для базы данных SQL Server. Кроме того, я тестирую его (модульные тесты) для базы данных SQLite.

Я выполнил это простым способом с помощью файла конфигурации. Итак, в моем классе, который расширяет DBContext, я реализовал OnConfiguring примерно так:

if(isSqlServer) //don't mind where it comes from, it works fine
    optionsBuilder.UseSqlServer(connectionString);
else
    optionsBuilder.UseSqlite(connectionString);

Кажется, работает нормально, но имеет нежелательный эффект. Предположим, у меня есть эти проекты:

  1. PersistenceLayer
  2. PersistenceLayerTests
  3. WebAPI

Поскольку метод UseSqlite является методом статического расширения в классе пакета Microsoft.EntityFrameworkCore.Sqlite и, аналогично, метод UseSqlServer является методом статического расширения в классе пакета Microsoft.EntityFrameworkCore.SqlServer, беспокоят две вещи я.

Во-первых, мне нужно включить обе зависимости в три проекта, чтобы избежать ошибки «System.IO.FileNotFoundException: не удалось загрузить файл или сборку Microsoft.EntityFrameworkCore.SqlServer (...)» во время выполнения.

Во-вторых, если мне нужно поддерживать новую СУБД (Oracle, MySQL), я должен включить новые зависимости в три проекта.

Я ожидал бы построить сценарий, в котором проект PersistentLayer не будет иметь этих зависимостей, в то время как PersistentLayerTests будет зависеть исключительно от Microsoft.EntityFrameworkCore.Sqlite, а WebAPI будет зависеть исключительно от Microsoft.EntityFrameworkCore.SqlServer.

Есть ли другой способ настройки контекста соединения, чтобы отделить зависимости этих пакетов?

Примечания:

  1. Я сделал это с NHibernate, который использует разные реализации драйверов для каждой СУБД.
  2. Я пытался использовать отражение, но это было не элегантно, и я заметил, что это не будет работать, если метод расширения имеет другие параметры.
  3. Мне не нужно полное решение. Если кто-то может указать мне другой путь, это будет очень полезно.

Ответы [ 2 ]

0 голосов
/ 12 сентября 2018

Это кажется излишним, но основная стратегия в таких случаях - создать общий интерфейс и разделить их в разных проектах.Не уверен, что это оптимальное решение для этого случая.

Тогда различные проекты независимы (за исключением общего интерфейса) и могут легко расширяться со временем.

Важнейшей частью являетсяв вашем основном проекте только ссылка на интерфейс сборки, а не на один из бетонов.Бетоны (сборки) должны быть загружены во время выполнения, если вы хотите избежать FileNotFoundException: более того: вам нужен механизм для выбора подходящего, обычно называемого factory.

.в случае, если у вас есть 3 из них (sql, sqllite и oracle):

Первое, что нужно сделать, - это создать общий интерфейс для связи с подходящим Db enginge, например:

//separate assembly
public interface IDbEningeSelector
{
    //added the option builder for simplicity: one could do better.
    void Configure(string connectionString,IOptionsBuilder optionsBuilder);
}

Далее просто создайте 3 отдельных проекта для конкретных реализаций: один sql-lite, один sql и один оракул.

Далее: создайте в трех проектах класс, который реализует это:

//3 of these.
public class SqlEnging : IDbEngineSelector
{
    public void Configure(string connectionString,IOptionsBuilder optionsBuilder)
    {
         optionsBuilder.UseSqlServer(connectionString);
    }
}

Хорошо, теперь у вас есть выбор, чтобы выбрать один из них.

//the "thing"
IDbEngineSelector selector = null;

selector = //resolve through factory, possibly based on a flag. 

selector.Configure(connectionString, optionsBuilder);

И в основном все готово, и у вас есть расширяемая, динамически называемая система провайдера базы данных.

Для распознавателя динамических сборок вам нужно будет загрузить их, как описано в этой статье: https://www.codeproject.com/Articles/1194332/Resolving-Assemblies-in-NET-Core

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

Я не учел детали реализации фабрики, мне нужно сначала проверить правильный способ сделать это в .net Core, подождать ...

0 голосов
/ 12 сентября 2018

Вам просто нужно, чтобы пользователи (проекты PersistenceLayerTests и WebApi) вашего DbContext отвечали за его настройку вместо самого DbContext .

DbContext предоставляет конструктор , принимающий DbContextOptions . Вам нужно выставить этот конструктор:

public class MyDbContext : DbContext
{
    public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) { }

    // ...
}

Тогда это позволит вам сделать следующее:

var optionsBuilder = new DbContextOptionsBuilder<MyDbContext>();

if (isSqlServer) //don't mind where it comes from, it works fine
    optionsBuilder.UseSqlServer(connectionString);
else
    optionsBuilder.UseSqlite(connectionString);

using (var context = new MyDbContext(optionsBuilder.Options))
{
    // ...
}
...