Entity Framework с большими системами - как разделить модели?

50

Я работаю с базой данных SQL Server с 1000+ таблицами, еще несколькими сотнями представлений и несколькими тысячами хранимых процедур. Мы надеемся начать использовать Entity Framework для наших новых проектов, и мы работаем над нашей стратегией для этого. Я зациклен на том, как лучше разбить таблицы на разные модели (EDMX или DbContext, если мы сначала перейдем к коду). Я могу придумать несколько стратегий сразу:

  • Разделение по
    схемам Наши таблицы разделены, вероятно, по дюжине схем. Мы могли бы сделать одну модель на схему. Это не идеально, потому что dbo по-прежнему очень большой, с 500+ таблицами / представлениями. Другая проблема заключается в том, что определенным единицам работы в конечном итоге придется выполнять транзакции, которые охватывают несколько моделей, что увеличивает сложность, хотя я предполагаю, что EF делает это довольно просто.
  • Разделение по назначению
    Вместо того, чтобы беспокоиться о схемах, разделите модели по назначению. Таким образом, у нас будут разные модели для каждого приложения, или проекта, или модуля, или экрана, в зависимости от степени детализации, которую мы хотим получить. Проблема, которую я вижу с этим, состоит в том, что есть определенные таблицы, которые неизбежно должны использоваться в каждом случае, такие как User или AuditHistory. Добавляем ли мы их в каждую модель (я думаю, что это нарушает «СУХОЙ»), или они в отдельной модели, используемой в каждом проекте?
  • Совсем не разделяйте - одна гигантская модель.
    Это очевидно просто с точки зрения разработки, но, исходя из моих исследований и моей интуиции, кажется, что это может работать ужасно, как во время разработки, так и во время компиляции и, возможно, во время выполнения.

Как лучше всего использовать EF для такой большой базы данных? В частности, какие стратегии используют люди при разработке моделей для этого объема объектов БД? Есть ли варианты, которые я не думаю об этой работе лучше, чем у меня выше?

Кроме того, это проблема в других ORM, таких как NHibernate? Если так, то они придумали какие-нибудь лучшие решения, чем EF?

RationalGeek
источник
«Необходимость выполнять транзакции, охватывающие несколько моделей, что увеличивает сложность». Просто обратите внимание, что вам необходимо включить координатор распределенных транзакций Microsoft. Как только вы это запустите, вам будет просто выполнить то, о чем вы говорите.
Tjaart
@ Спасибо, спасибо. Я использовал MS DTC раньше, и хотя он довольно прост, он добавляет сложности помимо простой базы данных txn, поэтому я хочу избегать ее, когда это возможно.
RationalGeek
2
4 года спустя, что вы решили и что бы вы порекомендовали сейчас?
Рори

Ответы:

31

Лично я попытался создать одну огромную схему для всех моих сущностей в довольно сложном, но небольшом проекте (~ 300 таблиц). У нас была чрезвычайно нормализованная база данных (нормализация 5-й формы (я говорю это в общих чертах)) со многими связями «многие ко многим» и принудительным соблюдением ссылочной целостности.

Мы также использовали стратегию «один экземпляр на запрос», которая, я не уверен, тоже помогла.

При выполнении простых, достаточно плоских «явно определенных» списков поиск и сохранение производительности в целом были приемлемыми. Но когда мы начали копаться в глубоких отношениях, представление, казалось, резко упало. По сравнению с хранимым процессом в этом случае сравнение не проводилось (конечно). Я уверен, что мы могли бы скорректировать базу кода здесь и там, чтобы улучшить производительность, однако в этом случае нам просто нужно было повысить производительность без анализа из-за нехватки времени, и мы вернулись к хранимому процессу (все еще отображая его через EF, потому что EF предоставил строго типизированные результаты), мы нуждались в этом только в качестве отступления в нескольких областях. Когда нам пришлось пройтись по всей базе данных, чтобы создать коллекцию (без малейшего использования .include ()), производительность заметно снизилась, но, возможно, мы слишком много просили ...

Исходя из моего опыта, я бы порекомендовал создать отдельный .edmx для каждого намерения. Создавайте только то, что вы будете использовать, исходя из объема этой потребности. У вас могут быть несколько файлов EDMX меньшего объема для поставленных задач, а затем несколько больших, где вам нужно обходить сложные отношения для построения объектов. Я не уверен, где это волшебное место, но я уверен, что есть одно ... лол ...

Честно говоря, хотя, за исключением нескольких ловушек, которые мы как бы увидели (сложный обход), огромный .edmx работал нормально с «рабочей» точки зрения. Но вам придется остерегаться магии «исправления», которую контекст создает за сценой, если вы явно не отключаете ее. Помимо синхронизации .edmx при внесении изменений в базу данных ... иногда было проще стереть всю поверхность и заново создать объекты, что заняло около 3 минут, поэтому это не имело большого значения.

Это было все с EntityFramework 4.1. Мне было бы очень интересно услышать о вашем конечном выборе и опыте.

Что касается вашего вопроса о nHibernate, то, на мой взгляд, это вопрос червей, вы будете лаять по обе стороны забора ... Я слышал, что многие люди бьют EF ради битья, не работая через проблемы и понимание нюансов, уникальных для самого EF ... и хотя я никогда не использовал nHibernate на производстве, обычно, если вам нужно вручную и явно создавать такие вещи, как сопоставления, вы получите более ограниченный контроль, однако, если вы могу перетаскивать, генерировать и запускать CRUD'ы и запросы с использованием LINQ, я мог бы дать немного дерьма о гранулярности.

Надеюсь, это поможет.

hanzolo
источник
1
К вашему сведению - есть утилита картирования NHibernate, которая делает эти сопоставления ОЧЕНЬ простыми и автоматизированными.
Гандерс
@Ganders - У него есть пользовательский интерфейс и как он интегрируется в IDE? Я предполагаю, что вы указываете на источник данных, и он уважает ссылочную целостность и обход объектов и создает объекты сопоставления?
Hanzolo
1
Да, это так (GUI). У меня до сих пор не было никаких проблем. Использовали его на 4 или 5 разных проектах / сайтах. Примечание: я использую его с Fluent NHibernate, который выполняет сопоставление в коде c #, а не в файлах config / xml. Вот ссылка: nmg.codeplex.com
Гандерс
13

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

Итак, у вас есть БОЛЬШАЯ база данных, и вы хотите использовать ее с ORM / EF. Я бы пошел со вторым выбором. Вот мое простое объяснение, почему:

  • Картирование добавляет сложности. Нет необходимости добавлять сложность к сущностям, в которых ваше текущее приложение / проект / модуль никогда не нуждается, но не делайте детализацию слишком низкой. Отдельное сопоставление для каждого экрана также не поможет.
  • Вы хотите достичь единицы работы. Вы должны быть в состоянии указать, какой модуль таблиц нужен в большинстве случаев (не обязательно во всех случаях). Если вы поместите эти таблицы в один набор сопоставлений, вы сможете обрабатывать чтение и изменение данных одним экземпляром контекста - это то, что должно быть вашей конечной целью.
  • Я не уверен, что именно вы подразумеваете под моделью, но даже с разными наборами сопоставлений вы можете совместно использовать классы между наборами сопоставлений, используя одни и те же типы сущностей. Поэтому, если вы используете таблицу User в двух модулях, вам не нужно два класса User для представления одного и того же. Вы по-прежнему можете использовать одну таблицу, а в случае отображения кода (он же сначала код) вы можете даже определить отображение один раз и загрузить его в несколько наборов отображений, чтобы принцип DRY не нарушался, а подход кода сначала имел больше ограничений, когда он возникает. для просмотра и хранимых процедур. EDMX делает это сложнее. Вы все еще можете повторно использовать классы, но повторное использование карт невозможно.
  • Как насчет межмодульных запросов? Эти запросы могут происходить, но, честно говоря, не все должно обрабатываться EF. Вы можете воспользоваться EF для обычных случаев, чтобы упростить регулярный доступ к данным, но если вам где-то нужен специальный запрос, объединяющий таблицы, принадлежащие 5 различным модулям, вы можете просто выполнить его напрямую или обернуть в хранимую процедуру. 100% замена нативного доступа к данным может быть сложной, сложной и непродуктивной.
  • Последний пункт просто практичен: я не верю, что инструментальные средства VS готовы работать с таким большим набором объектов - не в дизайнере, даже не с инструментом импорта. Раньше я работал над очень большой базой данных с традиционным доступом к данным и проектом SQL Database в VS2008 - пользовательский опыт со сложным проектом был очень плохим. Вы должны держать количество используемых таблиц небольшим - ограничение для дизайнера должно быть где-то между 100-200, но даже 100 таблиц, обрабатываемых одним контекстом (набором отображений), звучит как слишком большая ответственность для одного класса (предположим, что у вас будет 100 установленных свойств выставлено в контексте - это не похоже на хороший дизайн).
Ладислав Мрнка
источник
4

Я бы сказал, что вы не можете решить этот вопрос с технической точки зрения. Я бы порекомендовал вам строить свою архитектуру на основе ваших вариантов использования (пользовательских историй и т. Д.). Сначала найдите ваши бизнес-объекты. Объектный объект по умолчанию не является бизнес-объектом. Обычно у вас будет бизнес-объект перед объектами сущности. Затем вы можете постепенно решать, что вам действительно нужно, исходя из требований пользователя.

«Хороший архитектор максимизирует количество не принятых решений». Роберт С. Мартин

http://cleancoder.posterous.com/architecture-deference

ollins
источник
3

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

Nik
источник
Это кажется хорошей стратегией, но на самом деле не решает вопрос о том, как разделить сущности между различными моделями EF. У вас есть все сущности в одной модели или вы разделяете и побеждаете каким-то образом?
RationalGeek
1
Если производительность OLTP достаточна для подхода с полной моделью, воспользуйтесь этим. Вы всегда можете разбить его позже, если потребуется, но самый быстрый и гибкий способ - загрузить все это. Возможно, вам никогда не понадобится увеличение производительности, которое вы получите, разбив его на части, так что вам придется тратить время и усложнять вашу систему без всякой причины. Тогда возникает вопрос, к какой модели вы будете привязывать новую таблицу / сущность, когда решите расширяться. И что происходит, когда вам нужно запустить обновление для нескольких моделей. Избавьте себя от головной боли, если у вас нет альтернативы.
Ник
Забыл упомянуть, что вы всегда можете настроить свою производительность при доступе к вашим данным. Посмотрите на варианты отложенной / активной загрузки и какие дочерние объекты вы вводите. Я не вижу причин, почему полная модель будет вести себя хуже, чем меньшая, если вы не загружаете массивные деревья объектов.
Ник
я бы сказал, массивные объектные деревья и нормализованная структура данных идут рука об руку, когда имеешь дело с большими схемами
hanzolo
Вы контролируете, насколько мало или насколько вы хотите насытить объектный граф.
Ник