На сегодняшний день у меня сложилось впечатление, что a DbContext
предназначен для представления вашей базы данных, и поэтому, если ваше приложение использует одну базу данных, вам нужна только одна DbContext
.
Однако некоторые коллеги хотят разбить функциональные области на отдельные DbContext
классы.
Я полагаю, что это происходит из хорошего места - из-за желания содержать код в чистоте - но оно кажется нестабильным. Моя интуиция говорит мне, что это плохая идея, но, к сожалению, мое внутреннее чувство не является достаточным условием для дизайнерского решения.
Поэтому я ищу:
А) конкретные примеры того, почему это может быть плохой идеей;
Б) заверения, что все будет хорошо.
Ответы:
Вы можете иметь несколько контекстов для одной базы данных. Это может быть полезно, например, если ваша база данных содержит несколько схем баз данных, и вы хотите обрабатывать каждую из них как отдельную автономную область.
Проблема в том, что если вы хотите сначала использовать код для создания базы данных - это может сделать только один контекст в вашем приложении. Уловка для этого - обычно один дополнительный контекст, содержащий все ваши сущности, который используется только для создания базы данных. В реальных контекстах приложения, содержащих только подмножества ваших сущностей, инициализатору базы данных должно быть присвоено значение null.
Есть и другие проблемы, которые вы увидите при использовании нескольких типов контекста - например, общие типы сущностей и их передача из одного контекста в другой и т. Д. Как правило, это может сделать ваш дизайн намного чище и отделить различные функциональные области, но в нем есть стоит в дополнительной сложности.
источник
Enable-Migrations -ContextTypeName MyContext -MigrationsDirectory Migrations\MyContextMigrations
работает сейчас.Я написал этот ответ около четырех лет назад, и мое мнение не изменилось. Но с тех пор на фронте микросервисов произошли значительные события. В конце я добавил заметки для микро-сервисов ...
Я буду взвешивать эту идею, имея реальный опыт, чтобы поддержать мой голос.
Меня привлекло большое приложение, в котором было пять контекстов для одной базы данных. В конце концов, мы удалили все контексты, кроме одного - возвращаясь к одному контексту.
Сначала идея множественных контекстов кажется хорошей идеей. Мы можем разделить наш доступ к данным на домены и предоставить несколько простых и понятных контекстов. Похоже, DDD, верно? Это упростило бы наш доступ к данным. Другой аргумент в пользу производительности - доступ к контексту, который нам нужен.
Но на практике, по мере роста нашего приложения, многие из наших таблиц имели общие отношения в разных контекстах. Например, запросы к таблице A в контексте 1 также требовали присоединения к таблице B в контексте 2.
Это оставило нам пару неудачных вариантов. Мы могли бы дублировать таблицы в разных контекстах. Мы попробовали это. Это создало несколько проблем с отображением, включая ограничение EF, которое требует, чтобы у каждого объекта было уникальное имя. Таким образом, мы получили сущности с именами Person1 и Person2 в разных контекстах. Можно утверждать, что это был плохой дизайн с нашей стороны, но, несмотря на все наши усилия, наше приложение действительно росло в реальном мире.
Мы также попытались запросить оба контекста, чтобы получить нужные нам данные. Например, наша бизнес-логика будет запрашивать половину того, что ей нужно, из контекста 1, а другую половину - из контекста 2. У этого были некоторые серьезные проблемы. Вместо того, чтобы выполнять один запрос к одному контексту, нам пришлось выполнять несколько запросов в разных контекстах. Это реальное снижение производительности.
В конце концов, хорошая новость заключается в том, что было легко исключить несколько контекстов. Контекст предназначен для облегченного объекта. Поэтому я не думаю, что производительность является хорошим аргументом для нескольких контекстов. Я полагаю, что почти во всех случаях один контекст проще, менее сложен и, вероятно, будет работать лучше, и вам не придется реализовывать несколько обходных путей, чтобы заставить его работать.
Я подумал об одной ситуации, когда несколько контекстов могут быть полезны. Отдельный контекст можно использовать для устранения физической проблемы с базой данных, в которой она фактически содержит более одного домена. В идеале контекст должен быть один к одному для домена, который будет один к одному для базы данных. Другими словами, если набор таблиц никоим образом не связан с другими таблицами в данной базе данных, их, вероятно, следует извлечь в отдельную базу данных. Я понимаю, что это не всегда практично. Но если набор таблиц настолько отличается, что вам будет удобно разделить их на отдельную базу данных (но вы не захотите), тогда я мог бы рассмотреть возможность использования отдельного контекста, но только потому, что на самом деле есть два отдельных домена.
Что касается микросервисов, единый контекст все еще имеет смысл. Однако для микроуслуг каждый сервис будет иметь свой собственный контекст, который включает только таблицы базы данных, относящиеся к этому сервису. Другими словами, если служба x обращается к таблицам 1 и 2, а служба y обращается к таблицам 3 и 4, каждая служба будет иметь свой собственный уникальный контекст, который включает в себя таблицы, специфичные для этой службы.
Мне интересны ваши мысли.
источник
Эта тема только что всплыла на StackOverflow, и поэтому я хотел предложить еще одну «Б) гарантию, что все будет хорошо» :)
Я делаю именно это с помощью шаблона ограниченного контекста DDD. Я написал об этом в своей книге, Programming Entity Framework: DbContext, и он является основным 50-минутным модулем в рамках одного из моих курсов по Pluralsight -> http://pluralsight.com/training/Courses/TableOfContents/efarchitecture.
источник
Различение контекстов путем установки схемы по умолчанию
В EF6 вы можете иметь несколько контекстов, просто укажите имя для схемы базы данных по умолчанию в
OnModelCreating
методе вашегоDbContext
производного класса (где конфигурация Fluent-API). Это будет работать в EF6:В этом примере в качестве префикса для таблиц базы данных будет использоваться «Клиент» (вместо «dbo»). Что еще более важно это также префикс
__MigrationHistory
таблицы (таблиц), напримерCustomer.__MigrationHistory
. Таким образом, вы можете иметь более одной__MigrationHistory
таблицы в одной базе данных, по одной для каждого контекста. Таким образом, изменения, которые вы делаете для одного контекста, не будут мешать другому.При добавлении миграции укажите полное имя вашего класса конфигурации (производного от
DbMigrationsConfiguration
) в качестве параметра вadd-migration
команде:Короткое слово о ключе контекста
Согласно этой статье MSDN « Глава - Несколько моделей, нацеленных на одну и ту же базу данных », EF 6, вероятно, справится с ситуацией, даже если существует только одна
MigrationHistory
таблица, потому что в таблице есть столбец ContextKey, чтобы различать миграции.Однако я предпочитаю иметь более одной
MigrationHistory
таблицы, указав схему по умолчанию, как описано выше.Использование отдельных папок миграции
В таком случае вы также можете работать с разными папками «Миграция» в своем проекте. Вы можете настроить свой
DbMigrationsConfiguration
производный класс соответственно, используяMigrationsDirectory
свойство:Резюме
В общем, вы можете сказать, что все четко разделено: контексты, папки миграции в проекте и таблицы в базе данных.
Я бы выбрал такое решение, если есть группы сущностей, которые являются частью большой темы, но не связаны (через внешние ключи) друг с другом.
Если группы сущностей не имеют ничего общего друг с другом, я бы создал отдельную базу данных для каждого из них, а также получил бы к ним доступ в разных проектах, возможно, с одним единственным контекстом в каждом проекте.
источник
Простой пример для достижения ниже:
Просто поместите свойства в основной контекст: (используется для создания и обслуживания БД). Примечание. Просто используйте защищенный: (Сущность здесь не раскрывается).
MonitorContext: выставить отдельную сущность здесь
Модель диагностики:
Если вы хотите, вы можете пометить все сущности как защищенные внутри основного ApplicationDbContext, а затем создать дополнительные контексты по мере необходимости для каждого разделения схем.
Все они используют одну и ту же строку подключения, однако используют отдельные подключения, поэтому не пересекайте транзакции и не забывайте о проблемах блокировки. Как правило, ваше дизайнерское разделение, так что это не должно произойти в любом случае.
источник
DbSet<x>
определение вручную . Я делаю это в частичном классе, соответствующем тому, что делает EF Designer.Напоминание: если вы объединяете несколько контекстов, убедитесь, что вы вырезали и вставили все функциональные возможности
RealContexts.OnModelCreating()
в свой синглCombinedContext.OnModelCreating()
.Я просто потратил время на поиски, почему мои отношения каскадного удаления не были сохранены, только чтобы обнаружить, что я не перенес
modelBuilder.Entity<T>()....WillCascadeOnDelete();
код из моего реального контекста в мой комбинированный контекст.источник
OtherContext.OnModelCreating()
из вашего комбинированного контекста?Мой кишечник сказал мне то же самое, когда я наткнулся на этот дизайн.
Я работаю над базой кода, где есть три dbContexts для одной базы данных. 2 из 3 dbcontext зависят от информации из 1 dbcontext, поскольку она обслуживает административные данные. Этот дизайн наложил ограничения на то, как вы можете запрашивать ваши данные. Я столкнулся с этой проблемой, когда вы не можете объединиться через dbcontexts. Вместо этого вам необходимо запросить два отдельных dbcontexts, затем выполнить объединение в памяти или выполнить итерацию по обоим, чтобы получить комбинацию двух в качестве результирующего набора. Проблема в том, что вместо того, чтобы запрашивать конкретный набор результатов, вы теперь загружаете все свои записи в память, а затем выполняете соединение с двумя наборами результатов в памяти. Это действительно может замедлить ход событий.
Я бы задала вопростолько потому, что ты можешь, не так ли? «
См. Эту статью о проблеме, с которой я столкнулся, связанной с этим дизайном. Указанное выражение LINQ содержит ссылки на запросы, связанные с различными контекстами
источник
Вдохновленный [@JulieLerman's DDD MSDN Mag Article 2013] [1]
источник
В коде сначала вы можете иметь несколько DBContext и только одну базу данных. Вам просто нужно указать строку подключения в конструкторе.
источник
Еще немного «мудрости». У меня есть база данных, как Интернет, так и внутреннее приложение. У меня есть контекст для каждого лица. Это помогает мне сохранять дисциплинированную, защищенную сегрегацию.
источник
Я хочу поделиться случаем, когда я думаю, что возможность иметь несколько DBContexts в одной базе данных имеет смысл.
У меня есть решение с двумя базами данных. Один для данных домена, кроме информации о пользователе. Другой предназначен исключительно для информации пользователя. Это разделение главным образом обусловлено Общим регламентом ЕС о защите данных . Имея две базы данных, я могу свободно перемещать данные домена (например, из Azure в мою среду разработки), пока пользовательские данные остаются в одном безопасном месте.
Теперь для пользовательской базы данных я реализовал две схемы через EF. Один из них по умолчанию предоставляется платформой AspNet Identity. Другой - наша собственная реализация чего-либо еще, связанного с пользователем. Я предпочитаю это решение расширению схемы ApsNet, потому что я легко могу справиться с будущими изменениями в AspNet Identity, и в то же время разделение дает понять программистам, что «наша собственная пользовательская информация» идет в определенной пользовательской схеме, которую мы определили ,
источник
Да, потратил довольно много времени на проблему с отдельными контекстами БД для каждой схемы БД, надеюсь, что это поможет кому-то еще ...
Недавно я начал работать над проектом, в котором была одна база данных с 3-мя схемами (первый подход к БД), одна из которых предназначена для управления пользователями. Существовал контекст БД из каждой отдельной схемы. Конечно, пользователи были связаны и с другими схемами, например. схема KB имела таблицу Topic, в которой были «созданы», «последние изменены» и т. д. FK для идентификатора схемы, таблица appuser.
Эти объекты были загружены отдельно в C #, во-первых, тема была загружена из 1 контекста, затем пользователи были загружены через идентификаторы пользователей из другого контекста БД - не приятно, это нужно исправить! (аналогично использованию нескольких dbcontexts в одной базе данных с EF 6 )
Сначала я попытался добавить недостающие инструкции FK из схемы идентификации в схему KB, в EF modelBuilder в контексте базы данных KB. Так же, как если бы был только 1 контекст, но я разделил его на 2.
Это не сработало, поскольку в контексте kb db не было никакой информации об объекте пользователя, postgres вернул ошибку
relation "AppUsers" does not exist
. Оператор select не имеет правильной информации о схеме, именах полей и т. Д.Я почти сдался, но затем я заметил переключатель "-d" при запуске
dotnet ef dbcontext scaffold
. Его сокращение от -data-annotations - Используйте атрибуты для настройки модели (где это возможно). Если опущено, используется только свободный API. С этим указанным параметром свойства объекта были определены не в контексте БДOnModelCreating()
, а скорее в самом объекте с атрибутами.Таким образом, EF получил достаточно информации для генерации правильного оператора SQL с правильными именами полей и схемами.
TL; DR: отдельные контексты БД плохо обрабатывают отношения (FK) между ними, каждый контекст имеет информацию только о своих собственных сущностях. При указании включения «-data-annotations»
dotnet ef dbcontext scaffold
эта информация хранится не в каждом отдельном контексте, а в самих объектах БД.источник