Конфигурация DBContext генерирует ошибку конфигурации

Я пытаюсь использовать это DbContext в методе POST для добавления записи.

Конструктор контроллера с этим методом выглядит следующим образом:

public CookieController(ILogger<CookieController> logger, ICookieRepository cookieRepository)
{
    _logger = logger;
    _cookieRepository = cookieRepository;
}

Вот метод:

[HttpPost(Name = "")]
public IEnumerable<Cookie> PostCookie([FromBody] Cookie data)
{
    DbContextOptions<ReactWithASPDbContext> options = new DbContextOptions<ReactWithASPDbContext>();

    ReactWithASPDbContext dbContext = new ReactWithASPDbContext(options);

    // ...
}

Класс DbContext выглядит так:

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

   // ...
}

Это код Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<ReactWithASPDbContext>(options => { 
    options.UseSqlServer(

builder.Configuration["ConnectionStrings:ReactWithASPDbContextConnection"]); });

var app = builder.Build();
DbInitializer.Seed(app);

Это метод DbInitializer, и он работает:

public static void Seed(IApplicationBuilder applicationBuilder)
{
    ReactWithASPDbContext context = 
         applicationBuilder.ApplicationServices
                           .CreateScope()
                           .ServiceProvider
                           .GetRequiredService<ReactWithASPDbContext>();

    // ...
}

appsettings.json имеет следующее содержание:

"ConnectionStrings": {
   "ReactWithASPDbContextConnection": "Server= 

(localdb)\mssqllocaldb;Database=ReactWithASP;Trusted_Connection=True;MultipleActiveResultSets=True" }

Но конфигурация генерирует эту ошибку:

Для этого DbContext не настроен ни один поставщик базы данных. Поставщика можно настроить, переопределив метод DbContext.OnConfiguring или используя AddDbContext в поставщике службы приложения. Если используется «AddDbContext», также убедитесь, что ваш тип DbContext принимает объект DbContextOptions в своем конструкторе и передает его базовому конструктору для DbContext.

Я предполагаю, что мне не нужно воссоздавать материал инициализации в файле Program.cs, который создает IApplicationBuilder и т. д. Должен быть способ передать контекст после его создания, верно?

Эрк, большинство людей не так информируют свой контроллер о контексте базы данных, который будет использоваться в их методе PostXxx.

flackoverstow 05.06.2024 18:46

Почему ваш инициализатор БД «работает», если вы еще нигде не настроили, какую строку подключения должен использовать контекст? Вы хотите сказать, что Seed правильно заполняет нужную БД данными?

flackoverstow 05.06.2024 18:51

Да, метод семян работает.

John 05.06.2024 18:54

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

flackoverstow 05.06.2024 19:00

Просто добавил конструктор

John 05.06.2024 19:04

Хорошо, есть ли у ICookieRepository конструктор, который имеет этот контекст в качестве параметра? Или, может быть, у контроллера есть свойство, которое представляет собой контекст БД, украшенный атрибутом внедрения? (Похоже, вы выполнили необходимые настройки для DI, чтобы создать для вас контекст, подключенный к БД, но я еще не видел, где вы вводите его в контроллер с помощью DI)

flackoverstow 05.06.2024 19:07

Класс CookieRepository имеет такой конструктор: public CookieRepository(ReactWithASPDbContext actWithASPDbContext) { _reactWithASPDbContext = actWithASPDbContext; }

John 05.06.2024 19:08

Итак, в вашем методе PostCookie вы не будете создавать экземпляр контекста, вы будете вызывать методы в репозитории cookie, а репозиторий cookie будет использовать внедренный контекст для выполнения работы с БД. Не выполняйте работу с БД в контроллере, если у вас есть репозиторий, который выполняет работу с БД, к которой контроллер должен обращаться (и если у вас есть уровень обслуживания, не выполняйте работу с репозиторием в контроллере)

flackoverstow 05.06.2024 19:10
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
8
54
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Это говорит вам, что вы не добавили что-то подобное

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseSqlServer(_connectionString);
}

как в

public class SomeContext: DbContext
{

    private readonly string _connectionString;

    public SomeContext(string connString) : base()
    {
        _connectionString= connString;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(_connectionString);
    }

    // Add DB sets here

}

И connString — это имя этой переменной в appsettings.json, верно? Разве это не должно быть инициализировано? И это вместо текущего конструктора? Или в дополнение к этому?

John 05.06.2024 18:37

Извлеките эти данные из конфигурации при запуске, где вы настраиваете свой DI и остальные службы, и вызовите AddDbContext. Используйте DI, чтобы передать экземпляр контекста конструктору вашего контроллера или введенным реквизитам и использовать его. Не сохраняйте контекст в течение длительного времени (не делайте ничего, что приведет к тому, что он станет одноэлементным).

flackoverstow 05.06.2024 18:49

Извините, но не могли бы вы показать мне пример? Это единственный способ, которым я видел это в примере, который я использовал.

John 05.06.2024 18:50

@John Джон Как хранить строку подключения, решать вам. Если хранить в appsettings - отлично. Сохраняем в секретном менеджере. И еще по поводу ДИ. Есть еще один ответ, показывающий, как это сделать с помощью DI. Это один из способов. Есть другой способ, где вы вместо .Services.AddDbContext используете обычный .AddTransient и можете добавить фабрику контекста БД. Затем в вашем контроллере вы можете вызвать контекст, например using (var ctx = CtxFactory.Create()) { // do something } . Я использую фабричный стиль, потому что он помогает поддерживать несколько механизмов БД с помощью одной базы кода.

T.S. 05.06.2024 19:05

вам нужно настроить DbContext в Program.cs


// You already have this
var builder = WebApplication.CreateBuilder(args); 

// But you are missing this
builder.Services.AddDbContext<ReactWithASPDbContext>(
        options => options.UseSqlServer("name=ConnectionStrings:ReactWithASPDbContextConnection"));

Как только это будет сделано, вам нужно будет ввести ReactWithASPDbContext в свой контроллер, а не создавать его вручную.

public CookieController(ILogger<CookieController> logger, 
ICookieRepository cookieRepository, ReactWithASPDbContext context)
 {
  _logger = logger;
  _cookieRepository = cookieRepository;
  _context = context;
 }

  [HttpPost(Name = "")]
  public IEnumerable<Cookie> PostCookie([FromBody] Cookie data)
 {
  _context.DoSomething()
  ... 
 }

Это здесь. Я добавил это в пример.

John 05.06.2024 18:59

@Джон обновлен на основе ваших последних изменений.

ESG 05.06.2024 19:10

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

flackoverstow 05.06.2024 19:11

Я понимаю, что вы говорите, но описанный выше подход работает. Но не очень ремонтопригодно я так понимаю?

John 05.06.2024 19:15

Я так понимаю, вы имеете в виду, что функция добавления должна быть в классе Repo?

John 05.06.2024 19:19

Вопрос, который я пытаюсь решить, заключается в том, как заставить dbcontext работать. После этого обязательно посмотрите на различные шаблоны (например, репозиторий), которые помогут организовать код, но это выходит далеко за рамки первоначального запроса.

ESG 05.06.2024 19:22

Хорошо, я реализовал это с помощью репо, и это работает. Спасибо!!

John 05.06.2024 19:27

как заставить dbcontext работать - он уже работает ;) для работы просто нужно использовать то место, где он настроен, а не внедрять/создавать повсюду :D Но я так понимаю, это не очень удобно в обслуживании? - через пару лет вы оглянетесь назад и удивитесь тому, как изменился ваш инженерный подход. Это хорошая вещь

flackoverstow 05.06.2024 19:46

вы имеете в виду, что функция добавления должна быть в репо - да. Репозиторий отвечает за представление базового хранилища данных как единообразного интерфейса. Однажды вы можете решить перейти на хранение данных в текстовом файле или использовать интерфейс API, как если бы это была БД. Вместо этого вы переконфигурируете свое репо, чтобы сохранить его в текстовом файле. Add продолжал работать, но записывал в текстовый файл или сохранял в раскрывающемся списке и т. д., все продолжало его вызывать, несмотря на то, что данные передаются в другое место. Вы можете реализовать в своем репозитории интерфейс IBlahRepo, требующий добавления. Вы можете написать поддельный репо..

flackoverstow 05.06.2024 19:51

...для целей тестирования он просто хранит данные в памяти, красиво и быстро, их легко уничтожить. Он ведет себя так же, как ваш настоящий репо. Вы можете писать для него тесты, вызывать их и доказывать, что код, основанный на Add, будет работать, не разрушая при этом вашу БД. Вот почему мы создаем отдельные уровни с единообразными интерфейсами; чтобы мы могли заменить их на что-то другое, не нарушая остальную часть установки.

flackoverstow 05.06.2024 19:53

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

flackoverstow 05.06.2024 19:55

Другие вопросы по теме