Таким образом, ситуация, с которой я сталкиваюсь достаточно часто, - это ситуация, когда мои модели начинают либо:
- Вырасти в монстров с тоннами и тоннами методов
ИЛИ
- Позволяют вам передавать кусочки SQL им, чтобы они были достаточно гибкими и не требовали миллиона различных методов.
Например, скажем, у нас есть модель «виджет». Мы начнем с некоторых основных методов:
- получить ($ ID)
- вставить ($ запись)
- обновление ($ id, $ record)
- удаление ($ ID)
- getList () // получить список виджетов
Это все хорошо и здорово, но тогда нам нужно немного отчетности:
- listCreatedBetween ($ start_date, $ end_date)
- listPurchasedBetween ($ start_date, $ end_date)
- listOfPending ()
И тогда отчетность начинает усложняться:
- listPendingCreatedBetween ($ start_date, $ end_date)
- listForCustomer ($ customer_id)
- listPendingCreatedBetweenForCustomer ($ customer_id, $ start_date, $ end_date)
Вы можете видеть, где это растет ... в конце концов, у нас так много особых требований к запросу, что мне нужно либо реализовать тонны и тонны методов, либо какой-то объект "запроса", который я могу передать в один запрос -> запрос ( метод $ query) ...
... или просто прикусить пулю и начать делать что-то вроде этого:
- list = MyModel-> query ("start_date> X AND end_date <Y AND pending = 1 AND customer_id = Z")
Есть определенный призыв просто иметь один такой метод вместо 50 миллионов других более специфических методов ... но иногда кажется "неправильным" вставлять кучу того, что в основном является SQL, в контроллер.
Есть ли «правильный» способ справиться с такими ситуациями? Кажется ли приемлемым вставлять подобные запросы в общий метод -> query ()?
Есть ли лучшие стратегии?
источник
Ответы:
В паттернах корпоративной архитектуры приложений Мартина Фаулера описан ряд паттернов, связанных с ORM, включая использование объекта Query, что я и предложил бы.
Объекты запросов позволяют вам следовать принципу единой ответственности, разделяя логику для каждого запроса на индивидуально управляемые и поддерживаемые объекты стратегии. Либо ваш контроллер может управлять их использованием напрямую, либо делегировать это вторичному контроллеру или вспомогательному объекту.
У тебя их будет много? Конечно. Можно ли сгруппировать некоторые в общие запросы? Да еще раз.
Можете ли вы использовать внедрение зависимостей для создания объектов из метаданных? Это то, что делают большинство инструментов ORM.
источник
Там нет правильного способа сделать это. Многие люди используют ORM, чтобы абстрагироваться от всей сложности. Некоторые из более продвинутых ORM переводят выражения кода в сложные операторы SQL. У ORM есть и свои недостатки, однако для многих приложений преимущества перевешивают затраты.
Если вы не работаете с массивным набором данных, самое простое, что вы можете сделать, - это выделить всю таблицу в память и отфильтровать код.
Для приложений внутренней отчетности этот подход, вероятно, подойдет. Если набор данных действительно большой, вам понадобится множество пользовательских методов, а также соответствующие индексы в вашей таблице.
источник
Некоторые ORM позволяют создавать сложные запросы, начиная с базовых методов. Например
совершенно правильный запрос в Django ORM .
Идея состоит в том, что у вас есть какой-то конструктор запросов (в данном случае
Purchase.objects
), чей внутренний статус представляет информацию о запросе. Такие методы , какget
,filter
,exclude
,order_by
являются действительными и возвращают новый построитель запросов с обновленным статусом. Эти объекты реализуют итеративный интерфейс, поэтому при выполнении итерации по ним выполняется запрос, и вы получаете результаты построенного до сих пор запроса. Хотя этот пример взят из Django, вы увидите ту же структуру во многих других ORM.источник
Есть третий подход.
Ваш конкретный пример демонстрирует экспоненциальный рост числа методов, необходимых по мере роста количества требуемых функций: мы хотим иметь возможность предлагать расширенные запросы, объединяя каждую функцию запроса ... если мы делаем это путем добавления методов, у нас есть один метод для базовый запрос: два, если мы добавим одну дополнительную функцию, четыре, если мы добавим две, восемь, если мы добавим три, 2 ^ n, если мы добавим n функций.
Это, очевидно, недостижимо за пределами трех или четырех функций, и есть неприятный запах большого количества тесно связанного кода, который почти копируется между методами.
Этого можно избежать, добавив объект данных для хранения параметров и имея единственный метод, который строит запрос на основе набора предоставленных параметров (или не предоставленных). В этом случае добавление новой функции, такой как диапазон дат, так же просто, как добавление сеттеров и геттеров для диапазона дат в ваш объект данных, а затем добавление фрагмента кода для построения параметризованного запроса:
... и где параметры добавляются в запрос:
Этот подход обеспечивает линейный рост кода при добавлении функций без необходимости произвольных непараметрических запросов.
источник
Я думаю, что общее мнение заключается в том, чтобы максимально сохранить доступ к данным в ваших моделях в MVC. Один из других принципов разработки заключается в том, чтобы переместить некоторые из ваших более общих запросов (те, которые не имеют прямого отношения к вашей модели) на более высокий, более абстрактный уровень, где вы можете разрешить использовать его и в других моделях. (В RoR у нас есть что-то, что называется framework). Есть еще одна вещь, которую вы должны рассмотреть, и это - ремонтопригодность вашего кода. По мере роста вашего проекта, если у вас есть доступ к данным в контроллерах, его будет все труднее отслеживать (в настоящее время мы сталкиваемся с этой проблемой в огромном проекте). Модели, хотя и перегружены методами, обеспечивают единую точку контакта для любого контроллера, который может закончить тем, что запрашивает из таблиц. (Это также может привести к повторному использованию кода, что, в свою очередь, полезно)
источник
Ваш интерфейс уровня обслуживания может иметь много методов, но у вызова базы данных может быть только один.
База данных имеет 4 основных операции
Другим необязательным методом может быть выполнение некоторой операции с базой данных, которая не подпадает под основные операции с БД. Давайте назовем это Execute.
Вставка и обновления могут быть объединены в одну операцию, которая называется Сохранить.
Многие из ваших методов являются запросами. Таким образом, вы можете создать общий интерфейс для удовлетворения большинства насущных потребностей. Вот пример универсального интерфейса:
Объект передачи данных является общим и содержит все ваши фильтры, параметры, сортировку и т. Д., Содержащиеся в нем. Слой данных будет отвечать за разбор и извлечение данных и настройку операции для базы данных с помощью хранимых процедур, параметризованных sql, linq и т. Д. Таким образом, SQL не передается между слоями. Обычно это то, что делает ORM, но вы можете свернуть свое собственное и иметь свое собственное отображение.
Итак, в вашем случае у вас есть виджеты. Виджеты будут реализовывать интерфейс IPOCO.
Таким образом, в вашей модели уровня сервиса будет иметь
getList().
Потребовался бы слой отображения для обработки
getList
преобразования ви наоборот. Как уже упоминалось, иногда это делается с помощью ORM, но в конечном итоге вы получаете много типового кода, особенно если у вас есть сотни таблиц. ORM волшебным образом создает параметризованный SQL и запускает его для базы данных. При развертывании собственного, дополнительно в самом слое данных, мапперы понадобятся для настройки SP, linq и т. Д. (В основном, sql идет в базу данных).
Как упоминалось ранее, DTO - это объект, составленный композицией. Возможно, одним из объектов, содержащихся в нем, является объект с именем QueryParameters. Это будут все параметры запроса, которые будут установлены и использованы запросом. Другим объектом будет список возвращаемых объектов из запросов, обновлений, доп. Это полезная нагрузка. В этом случае полезной нагрузкой будет список виджетов List.
Итак, основная стратегия:
В вашем случае я думаю, что модель может иметь много методов, но оптимально вы хотите, чтобы вызов базы данных был универсальным. Вы по-прежнему получаете много стандартного кода отображения (особенно с SP) или магического кода ORM, который динамически создает параметризованный SQL для вас.
источник