Narowing не работает с динамическим доступом к объекту (доступ с помощью []
и переменной в качестве индекса). Это ограничение связано с производительностью. Вы можете искать в GitHub проблемы, связанные с этим, здесь один.
Почему, ох, почему индустрия так привязана к этой катастрофической концепции? Ни один из предыдущих ответов адекватно не решает проблемы @ johnny. Все они - наполовину выдуманные оправдания, которые избегают конкретных проблем, с которыми сталкиваются программисты баз данных.
Ответ @ TheTXI типичен для ответов, которые я получаю, когда задаю тот же вопрос: разделение слоев. Что это должно значить? Почему я хочу, чтобы разделял мои слои? Или, что более важно, какая польза от создания дополнительного уровня, который отличается от реляционного уровня и при этом должен быть каноническим отображением этого уровня?
Кроме того, (пока что оставшийся без ответа вопрос @johhny ) как это защищает нас от изменений? Если база данных изменится, уровень ORM почти наверняка последует этому примеру. Фактически, практика по умолчанию, при которой не моделируются таблицы соединений на уровне объекта, делает это еще хуже, потому что, когда таблица неизбежно вырастает несколько дополнительных столбцов, вы не только добавляете некоторые дополнительные поля в объектную модель, но также меняете ее топологию и принудительно куча кода переписать! Это катастрофа для управления изменениями и классический пример того, как ошибочный взгляд на отношения (думая, что они представляют собой объекты) приводит к катастрофе. Этого просто не произошло бы, если бы вы просто сопоставили реляционную базу данных непосредственно с совпадающими понятиями в языке программирования (подумайте о LINQ-to-SQL, а не , а не LINQ-to-EF).
Самый большой вопрос без ответа в этом пространстве - слон в комнате - это: какую проблему должна решить ORM? И не говорите «объектно-реляционное несоответствие импеданса». Это просто очередной размахивая руками. Объясните, почему существует несоответствие импеданса и почему именно база данных должна обращаться к языку, а не языку, передаваемому в базу данных. Мое объяснение состоит в том, что большинство языков программирования плохо справляются с выражением реляционных данных и работой с ними, но это историческая реальность, которая начинает ускользать (LINQ-to-SQL был первым маленьким шагом в этом направлении), а не фундаментальный принцип на которой основывается звуковая архитектура.
Есть причина, по которой ORM стали такими сложными, с отложенной загрузкой, кешированием, ошеломляющим набором семантики персистентности и владения и т.д. эффективно решать базовые задачи, такие как «Какие пары членов делят более одной группы?» Реляционная модель была задумана в то время, когда сетевые и иерархические модели ломались под тяжестью таких проблем; это был глоток свежего воздуха. Теперь все мы, кажется, жаждем вернуться в нашу старую песочницу, полную кошачьего моча, и думаем, что изобрели что-то новое (пока держим носы).
(Я полностью ожидаю, что этот ответ будет полностью отвергнут. Но, пожалуйста, оставьте комментарий, когда вы это сделаете. Я не возражаю, если мне скажут, что я неправ, если я знаю почему.)
РЕДАКТИРОВАТЬ : Спасибо, @Chris, за то, что нашли время прокомментировать. Это дает мне несколько конкретных вопросов ...(Обратите внимание, что, хотя я часто обращаюсь к @Chris ниже, я не пытаюсь дать ему конкретную задачу; его ответы типичны для тех комментариев, которые я слышу все время при обсуждении темы. Поэтому я надеюсь, что он не принимает мои критика как личное оскорбление; они не предназначены для этого, и я искренне ценю время, которое он потратил на ответ.)
Прежде всего, позвольте мне прояснить некоторые заблуждения, очевидные в комментариях и ответе @Cris.
Теперь некоторые возражения против возражений:
Мой собственный опыт работы с ORM показал, что они отлично работают в обучающих программах и вызывают бесконечную боль и разочарование в реальном мире. Поскольку LINQ-to-SQL устраняет многие проблемы, которые изначально мотивировали ORM, я не вижу причин подвергать себя таким пыткам.
Остается одна серьезная проблема: нынешний урожай баз данных SQL не предлагает какой-либо значимой степени контроля над разделением физического и логического уровней. Отображение таблицы на содержимое диска в значительной степени фиксировано и полностью находится под контролем СУБД SQL. Это не входило в план реляционной модели, которая явно разделяла эти две модели и позволяла определять согласованное логическое представление данных, которые могли бы храниться на диске в совершенно иной структуре, чем предполагалось в логической модели. Например, система (или dba) может физически денормализовать - по соображениям производительности - сильно нормализованную логическую модель. Поскольку механизмы SQL не допускают такого разделения задач, обычно денормализует или иным образом искажает логическую модель по чистой необходимости. В результате логические модели не всегда могут быть точно такими, какими должны, и поэтому идеал использования базы данных как наиболее чистого представления знаний не может быть полностью реализован. На практике, однако, дизайнеры в любом случае обычно придерживаются канонического отображения базы данных в модель предметной области, потому что все остальное слишком болезненно поддерживать.
Основным преимуществом использования инструментов ORM является упрощение принципа отделения бизнес-логики от доступа к данным в мульти приложение Если вы можете успешно построить слой доступа к данным, который реагирует на изменения в базе данных (путем изменения вашего отображения), вам не придется обходиться общим кодом при внесении изменений.
Разделение уровней обычно является целью трехуровневых или n-уровневых приложений, и ORM - хороший способ сделать это.
Основной драйвер: меньше общего кода для управления / обслуживания
1 вы получаете преимущество в том, что ваш уровень данных отделен от уровня объектов, поэтому, когда у вас есть несколько приложений / проектов в зависимости от этого слоя вы меняете его один раз в ORM, и все приложения / проекты, которые ссылаются на слой объекта, не должны изменяться, тогда как без него вам придется вносить изменения во все проекты.
По моему опыту работы с NHibernate, он немного похож на Visual Basic: он упрощает простые задачи на самом деле , но он также делает что-то более сложное, чем это на самом деле сложно или даже совершенно невозможно.
Основная идея состоит в том, что ORM позволяет избежать написания кода сохранения. В таком коде много дублирования, поэтому очень заманчиво сделать этот код универсальным, а не специфичным для конкретного бизнес-уровня, и повторно использовать его в проектах. Все идет нормально. Для простых иерархий объектов и бизнес-требований это действительно хорошо работает. Если ваша база данных изменяется, да, вам нужно изменить файлы сопоставления ORM, но обычно это довольно просто, и вам нужно внести изменение только в одном месте - намного проще, чем изменять код, который обращается к базе данных.
Проблема в том, что по мере того, как ваша база данных и требования становятся все более сложными, ORM становится все труднее успевать за ними. Таким образом, ORM становится все более и более сложной.Он также требует сокращений, делая некоторые вещи неэффективно, потому что он просто недостаточно умен, чтобы понять, как это сделать эффективно во всех случаях. Более того, поскольку вся идея заключается в том, что он работает прозрачно, вы часто не можете увидеть эти проблемы с производительностью, пока они не станут достаточно серьезными, чтобы повлиять на взаимодействие с пользователем. Связанная с этим проблема заключается в том, что ошибки найти намного сложнее, потому что вы просто не знаете, что происходит внутри ORM, если не отлаживаете его. (Да, мне пришлось пройти через код NHibernate, и это не пикник!)
Итак, вы начинаете обходить ORM для некоторых вещей и вместо этого напрямую используете SQL. Конечно, затем вы должны сделать так, чтобы код работал с кодом, который использует ORM, что требует больше работы. В конечном итоге вы пишете код для загрузки и сохранения некоторых объектов вручную и для того, чтобы каким-то образом включить это в код ORM. В конце концов, вы начинаете задаваться вопросом, создает ли ORM для вас больше работы, чем экономит, не говоря уже о производительности и проблемах с поиском ошибок.
Итак, если вы пишете очень простое приложение, подобное тому, которое вы найдете в учебнике, ORM подойдет. Если это сложнее, то, думаю, оно того не стоит. Конечно, для простого приложения абсолютная экономия времени также будет небольшой. Мой вывод: просто не заморачивайтесь с ORM. ORM - это путь, ведущий на темную сторону.
Я подробно ответил на ответ @Marcelo Cantos, однако я резюмирую основные преимущества использования ORM.
ORM идеально подходит для обоих этих общих шаблонов проектирования. Для правильного объектно-ориентированного дизайна вы будете работать с иерархическими и полиморфными объектами, чтобы выразить поток данных внутри вашего приложения. При хорошем дизайне вы часто будете стремиться к объектам POCO (простые старые объекты C / C #, я видел другие определения этого слова), потому что, если у меня есть человек, у которого есть список, я должен иметь именно его. У меня не должно быть DataTable лиц и DataTable адресов, которые я каким-то образом заставляю работать с моим приложением. Наряду с этим мне не нужно связывать тонны логики конкретной базы данных с моими объектами, почему поле FirstName моего человека должно иметь что-то вроде [ColumnName ("First_Name")] [Length (255)] [DataType (Types.Nvarchar)]
или любой другой набор безумных атрибутов или кода, который определяет, сколько существует баз данных, принудительно включенных в мой дизайн домена?
Число значительно сокращается строк кода, написанного, когда вы устраняете необходимость писать инструкции Select, Insert, Update и Delete для каждого отдельного объекта в вашем приложении, чтобы сохранить его в базе данных. Это оставляет вам только необходимость писать запросы, которые что-то значат. Также многие ORM (например, NHibernate) будут включать в себя язык, расположенный поверх SQL, который более определен для взаимодействия и может быть менее синтаксически заполнен обручами.
Наиболее полно это проявляется в приложении, у которого есть таблица UserTable, связанная с каждым отдельным объектом, и по какой-то причине вам НЕОБХОДИМО изменить имя или тип первичного ключа. На этом этапе вам потенциально может потребоваться изменить каждую хранимую процедуру в базе данных, где при правильно реализованном решении ORM вам нужно будет изменить только несколько сопоставлений конфигурации (или, возможно, ни одного), и это будет сделано.