N-слойное приложение базы данных без использования ORM. Как пользовательский интерфейс определяет, что ему нужно для отображения данных?

Я ищу указатели и информацию здесь, я сделаю это CW, так как я подозреваю, что у него нет ни одного правильного ответа. Это для C#, поэтому я сделаю несколько ссылок на Linq ниже. Я также прошу прощения за длинный пост. Позвольте мне обобщить вопрос здесь, а затем следует полный вопрос.

Описание: В четырехслойном приложении UI/BLL/DAL/DB, как можно изменить интерфейс пользователя, показать больше столбцов (скажем, в сетке), избежать утечки через уровень бизнес-логики и в уровень доступа к данным, чтобы получить данные для отображения (при условии, что они уже находятся в базе данных).


Давайте рассмотрим многоуровневое приложение с 3(4) слоями:

  • Пользовательский интерфейс
  • Уровень бизнес-логики (BLL)
  • Уровень доступа к данным (DAL)
  • База данных (БД; 4-й слой)

В этом случае DAL отвечает за построение операторов SQL и их выполнение в базе данных, возвращая данные.

Является ли единственный способ "правильно" создать такой слой, чтобы просто всегда делать "select *"? Для меня это большое нет-нет, но позвольте мне объяснить, почему мне интересно.

Допустим, я хочу, чтобы в моем пользовательском интерфейсе отображались все сотрудники, имеющие активную запись о занятости. Под "активным" я подразумеваю, что записи о занятости на сегодняшний день содержат сегодня (или, возможно, даже дату, которую я могу установить в пользовательском интерфейсе).

В этом случае, скажем, я хочу отправить электронное письмо всем этим людям, поэтому у меня есть код в BLL, который гарантирует, что я еще не отправил электронное письмо тем же людям и т. Д.

Для BLL требуется минимальное количество данных. Возможно, он вызывает слой доступа к данным, чтобы получить этот список активных сотрудников, а затем вызов, чтобы получить список отправленных им электронных писем. Затем он присоединяется к ним и создает новый список. Возможно, это можно сделать с помощью уровня доступа к данным, это не важно.

Важно то, что для бизнес-уровня действительно не так много данных, которые ему нужны. Возможно, ему просто нужен уникальный идентификатор для каждого сотрудника, для обоих списков, чтобы сопоставить его, а затем сказать: "Это уникальные идентификаторы тех, кто активен, и вы еще не отправили электронное письмо". Затем я создаю код DAL, который создает операторы SQL, которые получают только то, что нужно бизнес-уровню? То есть. просто "ВЫБЕРИТЕ идентификатор от сотрудников ГДЕ..."?

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

Как пользовательский интерфейс получает эти данные? Могу ли я изменить DAL, чтобы убедиться, что я возвращаю достаточно данных обратно в пользовательский интерфейс? Могу ли я изменить BLL, чтобы убедиться, что он возвращает достаточно данных для пользовательского интерфейса? Если объект или структуры данных, возвращенные из DAL обратно в BLL, могут быть также отправлены в пользовательский интерфейс, возможно, BLL не нуждается в особых изменениях, но тогда требования пользовательского интерфейса влияют на уровень, выходящий за пределы того, с чем он должен взаимодействовать., И если два мира работают с разными структурами данных, вероятно, придется внести изменения в оба.

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

Одно из предложенных предложений заключается в использовании Linq-To-SQL и IQueryable, так что если DAL, который имеет дело с тем, что (как в том, какие типы данных) и почему (как в предложениях WHERE) вернул IQueryables, BLL может потенциально вернуть их в пользовательский интерфейс, который затем может создать запрос Linq, который будет получать необходимые данные. Затем код пользовательского интерфейса может получить нужные столбцы. Это будет работать, поскольку с IQuerables пользовательский интерфейс будет фактически выполнять запрос, а затем он может использовать "select new { X, Y, Z }", чтобы указать, что ему нужно, и даже при необходимости присоединиться к другим таблицам.

Это выглядит грязно для меня. Пользовательский интерфейс выполняет сам код SQL, даже если он был скрыт за внешним интерфейсом Linq.

Но для этого BLL или DAL нельзя разрешать закрывать соединения с базой данных, а в мире типа IoC служба DAL может быть утилизирована немного раньше, чем хотелось бы коду UI, так что Запрос Linq может просто закончиться исключением: "Не удается получить доступ к удаленному объекту".

Поэтому я ищу указатели. Как далеко мы? Как вы справляетесь с этим? Я считаю тот факт, что изменения в пользовательском интерфейсе будут проходить через BLL и в DAL, очень плохое решение, но сейчас не похоже, что мы можем добиться большего успеха.

Пожалуйста, скажи мне, насколько мы глупы, и докажи, что я не прав?

И обратите внимание, что это устаревшая система. Изменение схемы базы данных в течение многих лет не входит в сферу применения, поэтому решение использовать объекты ORM, которые по сути делали бы эквивалент "select *", на самом деле не вариант. У нас есть несколько больших таблиц, которые мы хотели бы избежать, просматривая весь список слоев.

2 ответа

Решение

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

UI <-- (viewmodel) ---> BLL <-- (model) --> Peristence/Data layers

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

Это совсем не простая проблема. Я видел много попыток (включая описанный вами подход IQueryable), но ни одна из них не была идеальной. К сожалению, мы все еще ждем идеального решения. До тех пор нам придется обойтись без несовершенства.

Я полностью согласен с тем, что проблемы DAL не должны просачиваться в верхние слои, поэтому необходима изоляционная BLL.

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

Слишком гранулированные объекты могут привести к болтливым интерфейсам DAL, но слишком крупные объекты могут привести к загрузке слишком большого количества ненужных данных.

Очень важным упражнением является анализ и правильное моделирование агрегатов модели предметной области, чтобы они находили правильный баланс. Книга " Управляемый предметом дизайн" содержит некоторые очень интересные аналитические материалы о совокупных моделях моделирования.

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

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

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