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

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

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


Предположим, многоуровневое приложение с 3 (4) слоями:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Ответы [ 2 ]

3 голосов
/ 06 октября 2009

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

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

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

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

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

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

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

1 голос
/ 06 октября 2009

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...