Ядро C # Dotnet - проблемы с реализацией универсального DBContext в конструкторе - PullRequest
0 голосов
/ 28 апреля 2019

Я борюсь с этим возвращением после длительного увольнения.

Я задал вопрос относительно настройки DBContext в моем общем базовом репозитории. Только после того, как пользователь вошел в систему, я могу затем создать строку подключения, чтобы я не мог зарегистрировать службу в startup.cs - мне нужно использовать аргумент конструктора для создания экземпляра моего DBContext.

Я получил этот ответ , который, как я думал, решит проблему, однако я получаю сообщение об ошибке в следующем заводском классе:

public class ContextFactory<T> : IContextFactory<T> : where T : DbContext
{
    public T CreateDbContext(string connectionString)
    {
        var optionsBuilder = new DbContextOptionsBuilder<T>();
        optionsBuilder.UseSqlServer(connectionString);
        return new T(optionsBuilder.Options);
    }
}

Ошибка в строке возврата new T(optionsBuilder.Options); и составляет:

Невозможно создать экземпляр типа переменной 'T', потому что это не иметь новое () ограничение

1 Ответ

4 голосов
/ 28 апреля 2019

Даже если вы добавите ограничение new(), вы получите следующую ошибку

'T': невозможно предоставить аргументы при создании экземпляра типа переменной.

Вам дали неверный код.

Новое ограничение указывает, что любой аргумент типа в объявлении универсального класса должен иметь открытый конструктор без параметров. Чтобы использовать новое ограничение, тип не может быть абстрактным.

Ссылка Новое ограничение (C # Ссылка)

Другим вариантом, который следует рассмотреть, может быть использование Activator.CreateInstance (Type, Object []) .

Учитывая

public interface IContextFactory<TContext> where TContext : DbContext {
    TContext Create(string connectionString);
}

Вы бы реализовали это следующим образом

public class ContextFactory<TContext> : IContextFactory<TContext>
    where TContext : DbContext {

    public TContext Create(string connectionString) {
        var optionsBuilder = new DbContextOptionsBuilder<TContext>();
        optionsBuilder.UseSqlServer(connectionString);
        return (TContext)Activator.CreateInstance(typeof(TContext), optionsBuilder.Options);
    }
}

Это может быть изменено в дальнейшем для разделения проблем

public class ContextFactory<TContext> : IContextFactory<TContext>
    where TContext : DbContext {

    public TContext Create(DbContextOptions<TContext> options) {
        return (TContext)Activator.CreateInstance(typeof(TContext), options);
    }
}

так, чтобы строитель стал ответственным за то, где используется фабрика.

var connection = @"....";
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlServer(connection);

//Assuming factory is `IContextFactory<BloggingContext>`    
using (var context = factory.Create(optionsBuilder.Options))
{
   // do stuff
}

EDIT

Завод может быть зарегистрирован как открытый дженерик в ConfigureServices метод

services.AddSingleton(typeof(IContextFactory<>), typeof(ContextFactory<>));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...