#c# #architecture #entity-framework-core #multi-tenant #dbcontext
Вопрос:
Я унаследовал приложение .Net Framework, которое на самом деле не было разработано, но было создано как приложение портала для клиентов, но затем у каждого клиента есть своя собственная база данных для хранения своих данных по соображениям безопасности и суверенитета данных. Домашняя страница загружает основные данные из общей базы данных, но когда пользователи переходят на одну из страниц, сайту необходимо подключиться к их конкретной базе данных.
Приложение написано на C# с использованием Angular и свободно следует MVC, основной контекст передается через DI, и я только что обновил его до .Net 5. Поскольку могут существовать тысячи клиентских баз данных, которые не могут быть зарегистрированы в качестве служебных подключений при запуске, я пытаюсь найти наилучший способ обработки DbContext для этих клиентских баз данных. По-видимому, в целом он соответствует принципам многоквартирного дома, но следующие проблемы
- Избегая повторения кода или добавления большого количества «= новый DbContext » — использование DI было бы предпочтительнее, если это возможно, с помощью перехватчика TenantFactory или базы данных
- Убедитесь, что соединение предназначено для правильной базы данных, если у пользователя открыто несколько вкладок для разных клиентов
- Обеспечение удаления подключения к БД при закрытии клиентской страницы или возвращении пользователя домой для просмотра другого клиента
Я понимаю, что могу создавать новый контекст БД для каждого запроса, каждый раз передавая имя БД, но есть ли шаблон или пример, который лучше подходит для этого случая использования? Что-то вроде DbCommandInterceptor на уровне БД может сработать, но опять же, если есть несколько примеров того, как это сделать, я могу их найти.
Ответ №1:
Для контекста вашего клиента убедитесь, что вы используете одну из AddDbContext
перегрузок с областью optionsLifetime
действия . Затем вы можете предоставить другую строку подключения для каждого экземпляра, полученную из любой другой службы с областью действия.
services.AddDbContext<T>((sp, o) => {
var context = sp.GetService<IHttpContextAccessor>().Context;
o.UseSqlServer(... get the connection string here. From context.User? ...)
});
Ответ №2:
Самый простой, безопасный и лучший способ сделать это-именно то, что вы сказали. Создайте новый DbContext для каждого запроса, указав имя базы данных с помощью некоторого метода изоляции нескольких арендаторов.
DbContext предназначен для работы только в краткосрочной перспективе. Попытка сделать его живым дольше, чем запрос, создаст проблемы с памятью и безопасностью. НИКОГДА не создавайте статический (или одноэлементный) DbContext в многопользовательском приложении, таком как веб-сайт.
Наилучшей практикой является внедрение DbContext с жизненным циклом для каждого запроса. Это гарантирует, что DbContext будет уничтожен после завершения запроса, и вся память будет очищена.